| blib/lib/Digest/Auth.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 1 | 3 | 33.3 |
| branch | n/a | ||
| condition | n/a | ||
| subroutine | 1 | 1 | 100.0 |
| pod | n/a | ||
| total | 2 | 4 | 50.0 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package Digest::Auth; | ||||||
| 2 | |||||||
| 3 | # --- Required Packages | ||||||
| 4 | #use Carp; # Generate better errors with more context | ||||||
| 5 | 1 | 1 | 28622 | use DBI; # Database connector | |||
| 0 | |||||||
| 0 | |||||||
| 6 | use CGI; # For the cookie handeling and output tools. | ||||||
| 7 | use strict; # Enforce restictions on good programming | ||||||
| 8 | |||||||
| 9 | # --- Headers --- | ||||||
| 10 | my $PACKAGE = 'Auth'; | ||||||
| 11 | my $VERSION = '0.01_2'; | ||||||
| 12 | use vars qw($VERSION); | ||||||
| 13 | |||||||
| 14 | # Routines | ||||||
| 15 | sub new { | ||||||
| 16 | my $package = shift; | ||||||
| 17 | my %opts = @_; | ||||||
| 18 | my $class = ref($package) || $package; | ||||||
| 19 | |||||||
| 20 | my(%DM) = ( | ||||||
| 21 | session => { | ||||||
| 22 | table => "session", | ||||||
| 23 | ip => "ip", | ||||||
| 24 | cert => "cert", | ||||||
| 25 | hash => "hash", | ||||||
| 26 | userid => "userid", | ||||||
| 27 | firstactive => "firstactive", | ||||||
| 28 | lastactive => "lastactive", | ||||||
| 29 | }, | ||||||
| 30 | sessionlocks => { | ||||||
| 31 | table => "sessionlocks", | ||||||
| 32 | ip => "ip", | ||||||
| 33 | stamp => "stamp", | ||||||
| 34 | cert => "cert", | ||||||
| 35 | hash => "hash", | ||||||
| 36 | userid => "userid", | ||||||
| 37 | }, | ||||||
| 38 | sessionattempts => { | ||||||
| 39 | table => "sessionattempts", | ||||||
| 40 | ip => "ip", | ||||||
| 41 | stamp => "stamp", | ||||||
| 42 | cert => "cert", | ||||||
| 43 | hash => "hash", | ||||||
| 44 | userid => "userid", | ||||||
| 45 | password => "password", | ||||||
| 46 | }, | ||||||
| 47 | user => { | ||||||
| 48 | table => "user", | ||||||
| 49 | userid => "userid", | ||||||
| 50 | password => "password", | ||||||
| 51 | }, | ||||||
| 52 | ); | ||||||
| 53 | |||||||
| 54 | # Options hash init | ||||||
| 55 | my($self) = { | ||||||
| 56 | dbh => undef, # data base handel | ||||||
| 57 | debug => 0, # level of debug: 0=off,1=Error,2=Warn,3=Verbose | ||||||
| 58 | debuginfo => "", # store debug information here. | ||||||
| 59 | cookiename => "SessionCert", # Cookie name to use for authorization | ||||||
| 60 | domain => ".", # Domain name for cookie | ||||||
| 61 | usecookies => 1, # Use cookies to maintain sessions. | ||||||
| 62 | digest => "Digest::SHA1", # Hash Digest to use | ||||||
| 63 | connection => 86400, # Maximum length of a authorized session. Default 24 hours | ||||||
| 64 | validation => 600, # Maximum amout of time for validation process. Default 10 minutes | ||||||
| 65 | idletime => 3600, # Amount of time you can be inactive before being logged out. Default 60 minutes | ||||||
| 66 | initcertretry => 5, # number of times to retry intitializing a session if the key is a duplicate | ||||||
| 67 | forgiverate => 86400, # Forgive bad login attempts after this much time or good login | ||||||
| 68 | maxconperip => 10, # Max connections/sessions per ip address | ||||||
| 69 | maxconperuser => 1, # Max connections/sessions per user name | ||||||
| 70 | maxbadpass => 5, # Max number of times a user can enter a bad password | ||||||
| 71 | compatmode => 0, # WARNING: THIS REDUCES SECURITY: Change to 1 to enable compatibility for non-javascript browsers. | ||||||
| 72 | locklength => [300,900,3600,86400,-1], # Amount of time a user is locked/banned for a rule violation | ||||||
| 73 | datamapping => \%DM, # Data Mapping to modify the fieldnames for the database. | ||||||
| 74 | }; | ||||||
| 75 | bless($self, $class); | ||||||
| 76 | $self->DebugAdd($PACKAGE."->new()::Initialized",3); | ||||||
| 77 | my($bitbucket) = $self->Put(%opts); | ||||||
| 78 | return $self; | ||||||
| 79 | } | ||||||
| 80 | |||||||
| 81 | sub Get{ | ||||||
| 82 | my($self,$opt1,$opt2,$opt3) = @_; | ||||||
| 83 | my $result; | ||||||
| 84 | $self->DebugAdd($PACKAGE."->Get($opt1,$opt2,$opt3)::Initialized",3); | ||||||
| 85 | |||||||
| 86 | $opt1 =~ s/[^\w]//g; | ||||||
| 87 | $opt1 = lc($opt1); | ||||||
| 88 | |||||||
| 89 | $opt2 =~ s/[^\w]//g; | ||||||
| 90 | $opt2 = lc($opt2); | ||||||
| 91 | |||||||
| 92 | $opt3 =~ s/[^\w]//g; | ||||||
| 93 | $opt3 = lc($opt3); | ||||||
| 94 | |||||||
| 95 | if(exists $self->{$opt1}){ | ||||||
| 96 | if($opt1 eq "datamapping"){ | ||||||
| 97 | if(exists $self->{datamapping}{$opt2}){ | ||||||
| 98 | if(exists $self->{$opt1}{$opt2}{$opt3}){ | ||||||
| 99 | return $self->{$opt1}{$opt2}{$opt3}; | ||||||
| 100 | }else{ | ||||||
| 101 | return $result; # no result | ||||||
| 102 | } | ||||||
| 103 | }else{ | ||||||
| 104 | return $result; # no result | ||||||
| 105 | } | ||||||
| 106 | }else{ | ||||||
| 107 | return $self->{$opt1}; | ||||||
| 108 | } | ||||||
| 109 | }else{ | ||||||
| 110 | return $result; # no result | ||||||
| 111 | } | ||||||
| 112 | } | ||||||
| 113 | sub Put{ | ||||||
| 114 | my($self,%opt) = @_; | ||||||
| 115 | my($result)= 0; | ||||||
| 116 | $self->DebugAdd($PACKAGE."->Put()::Initialized",3); | ||||||
| 117 | |||||||
| 118 | if(exists $opt{dbh}){ | ||||||
| 119 | $result++; $self->{dbh} = $opt{dbh}; | ||||||
| 120 | } | ||||||
| 121 | if(exists $opt{debug} && $self->SanitizeData($opt{debug}) && $opt{debug} >= 0 && $opt{debug} <= 3){ | ||||||
| 122 | $result++; $self->{debug} = $opt{debug}; | ||||||
| 123 | } | ||||||
| 124 | if(exists $opt{digest}){ | ||||||
| 125 | $result++; $self->{digest} = $opt{digest}; | ||||||
| 126 | } | ||||||
| 127 | if(exists $opt{cookiename} && $self->SanitizeData($opt{cookiename},1)){ | ||||||
| 128 | $result++; $self->{cookiename} = $opt{cookiename}; | ||||||
| 129 | } | ||||||
| 130 | if(exists $opt{domain} && $self->SanitizeData($opt{domain},4)){ | ||||||
| 131 | $result++; $self->{domain} = $opt{domain}; | ||||||
| 132 | } | ||||||
| 133 | if(exists $opt{usecookies} && ($opt{usecookies} == 0 || $opt{usecookies} == 1)){ | ||||||
| 134 | $result++; $self->{usecookies} = $opt{usecookies}; | ||||||
| 135 | } | ||||||
| 136 | if(exists $opt{connection} && $self->SanitizeData($opt{connection},3)){ | ||||||
| 137 | $result++; $self->{connection} = $opt{connection}; | ||||||
| 138 | } | ||||||
| 139 | if(exists $opt{validation} && $self->SanitizeData($opt{validation},3)){ | ||||||
| 140 | $result++; $self->{validation} = $opt{validation}; | ||||||
| 141 | } | ||||||
| 142 | if(exists $opt{idletime} && $self->SanitizeData($opt{idletime},3)){ | ||||||
| 143 | $result++; $self->{idletime} = $opt{idletime}; | ||||||
| 144 | } | ||||||
| 145 | if(exists $opt{initcertretry} && $self->SanitizeData($opt{initcertretry})){ | ||||||
| 146 | $result++; $self->{initcertretry} = $opt{initcertretry}; | ||||||
| 147 | } | ||||||
| 148 | if(exists $opt{forgiverate} && $self->SanitizeData($opt{forgiverate})){ | ||||||
| 149 | $result++; $self->{forgiverate} = $opt{forgiverate}; | ||||||
| 150 | } | ||||||
| 151 | if(exists $opt{maxconperip} && $self->SanitizeData($opt{maxconperip},3)){ | ||||||
| 152 | $result++; $self->{maxconperip} = $opt{maxconperip}; | ||||||
| 153 | } | ||||||
| 154 | if(exists $opt{maxconperuser} && $self->SanitizeData($opt{maxconperuser},3)){ | ||||||
| 155 | $result++; $self->{maxconperuser} = $opt{maxconperuser}; | ||||||
| 156 | } | ||||||
| 157 | if(exists $opt{maxbadpass} && $self->SanitizeData($opt{maxbadpass},3)){ | ||||||
| 158 | $result++; $self->{maxbadpass} = $opt{maxbadpass}; | ||||||
| 159 | } | ||||||
| 160 | if(exists $opt{compatmode} && $self->SanitizeData($opt{compatmode}) && ($opt{compatmode} == 1 || $opt{compatmode} == 0)){ | ||||||
| 161 | $result++; $self->{compatmode} = $opt{compatmode}; | ||||||
| 162 | } | ||||||
| 163 | if(exists $opt{locklength} && $self->SanitizeData($opt{locklength},3)){ | ||||||
| 164 | $result++; $self->{locklength} = $opt{locklength}; | ||||||
| 165 | } | ||||||
| 166 | if(exists $opt{datamapping}{session}{table} && $self->SanitizeData($opt{datamapping}{session}{table},2)){ | ||||||
| 167 | $result++; $self->{datamapping}{session}{table} = $opt{datamapping}{session}{table}; | ||||||
| 168 | } | ||||||
| 169 | if(exists $opt{datamapping}{session}{ip} && $self->SanitizeData($opt{datamapping}{session}{ip},2)){ | ||||||
| 170 | $result++; $self->{datamapping}{session}{ip} = $opt{datamapping}{session}{ip}; | ||||||
| 171 | } | ||||||
| 172 | if(exists $opt{datamapping}{session}{cert} && $self->SanitizeData($opt{datamapping}{session}{cert},2)){ | ||||||
| 173 | $result++; $self->{datamapping}{session}{cert} = $self->{datamapping}{session}{cert}; | ||||||
| 174 | } | ||||||
| 175 | if(exists $opt{datamapping}{session}{hash} && $self->SanitizeData($opt{datamapping}{session}{hash},2)){ | ||||||
| 176 | $result++; $self->{datamapping}{session}{hash} = $opt{datamapping}{session}{hash}; | ||||||
| 177 | } | ||||||
| 178 | if(exists $opt{datamapping}{session}{userid} && $self->SanitizeData($opt{datamapping}{session}{userid},2)){ | ||||||
| 179 | $result++; $self->{datamapping}{session}{userid} = $opt{datamapping}{session}{userid}; | ||||||
| 180 | } | ||||||
| 181 | if(exists $opt{datamapping}{session}{firstactive} && $self->SanitizeData($opt{datamapping}{session}{firstactive},2)){ | ||||||
| 182 | $result++; $self->{datamapping}{session}{firstactive} = $opt{datamapping}{session}{firstactive}; | ||||||
| 183 | } | ||||||
| 184 | if(exists $opt{datamapping}{session}{lastactive} && $self->SanitizeData($opt{datamapping}{session}{lastactive},2)){ | ||||||
| 185 | $result++; $self->{datamapping}{session}{lastactive} = $opt{datamapping}{session}{lastactive}; | ||||||
| 186 | } | ||||||
| 187 | if(exists $opt{datamapping}{sessionlocks}{table} && $self->SanitizeData($opt{datamapping}{sessionlocks}{table},2)){ | ||||||
| 188 | $result++; $self->{datamapping}{sessionlocks}{table} = $opt{datamapping}{sessionlocks}{table}; | ||||||
| 189 | } | ||||||
| 190 | if(exists $opt{datamapping}{sessionlocks}{ip} && $self->SanitizeData($opt{datamapping}{sessionlocks}{ip},2)){ | ||||||
| 191 | $result++; $self->{datamapping}{sessionlocks}{ip} = $opt{datamapping}{sessionlocks}{ip}; | ||||||
| 192 | } | ||||||
| 193 | if(exists $opt{datamapping}{sessionlocks}{stamp} && $self->SanitizeData($opt{datamapping}{sessionlocks}{stamp},2)){ | ||||||
| 194 | $result++; $self->{datamapping}{sessionlocks}{stamp} = $opt{datamapping}{sessionlocks}{stamp}; | ||||||
| 195 | } | ||||||
| 196 | if(exists $opt{datamapping}{sessionlocks}{cert} && $self->SanitizeData($opt{datamapping}{sessionlocks}{cert},2)){ | ||||||
| 197 | $result++; $self->{datamapping}{sessionlocks}{cert} = $opt{datamapping}{sessionlocks}{cert}; | ||||||
| 198 | } | ||||||
| 199 | if(exists $opt{datamapping}{sessionlocks}{hash} && $self->SanitizeData($opt{datamapping}{sessionlocks}{hash},2)){ | ||||||
| 200 | $result++; $self->{datamapping}{sessionlocks}{hash} = $opt{datamapping}{sessionlocks}{hash}; | ||||||
| 201 | } | ||||||
| 202 | if(exists $opt{datamapping}{sessionlocks}{userid} && $self->SanitizeData($opt{datamapping}{sessionlocks}{userid},2)){ | ||||||
| 203 | $result++; $self->{datamapping}{sessionlocks}{userid} = $opt{datamapping}{sessionlocks}{userid}; | ||||||
| 204 | } | ||||||
| 205 | if(exists $opt{datamapping}{sessionattempts}{table} && $self->SanitizeData($opt{datamapping}{sessionattempts}{table},2)){ | ||||||
| 206 | $result++; $self->{datamapping}{sessionattempts}{table} = $opt{datamapping}{sessionattempts}{table}; | ||||||
| 207 | } | ||||||
| 208 | if(exists $opt{datamapping}{sessionattempts}{ip} && $self->SanitizeData($opt{datamapping}{sessionattempts}{ip},2)){ | ||||||
| 209 | $result++; $self->{datamapping}{sessionattempts}{ip} = $self->{datamapping}{sessionattempts}{ip}; | ||||||
| 210 | } | ||||||
| 211 | if(exists $opt{datamapping}{sessionattempts}{stamp} && $self->SanitizeData($opt{datamapping}{sessionattempts}{stamp},2)){ | ||||||
| 212 | $result++; $self->{datamapping}{sessionattempts}{stamp} = $opt{datamapping}{sessionattempts}{stamp}; | ||||||
| 213 | } | ||||||
| 214 | if(exists $opt{datamapping}{sessionattempts}{cert} && $self->SanitizeData($opt{datamapping}{sessionattempts}{cert},2)){ | ||||||
| 215 | $result++; $self->{datamapping}{sessionattempts}{cert} = $opt{datamapping}{sessionattempts}{cert}; | ||||||
| 216 | } | ||||||
| 217 | if(exists $opt{datamapping}{sessionattempts}{hash} && $self->SanitizeData($opt{datamapping}{sessionattempts}{hash},2)){ | ||||||
| 218 | $result++; $self->{datamapping}{sessionattempts}{hash} = $opt{datamapping}{sessionattempts}{hash}; | ||||||
| 219 | } | ||||||
| 220 | if(exists $opt{datamapping}{sessionattempts}{userid} && $self->SanitizeData($opt{datamapping}{sessionattempts}{userid},2)){ | ||||||
| 221 | $result++; $self->{datamapping}{sessionattempts}{userid} = $opt{datamapping}{sessionattempts}{userid}; | ||||||
| 222 | } | ||||||
| 223 | if(exists $opt{datamapping}{sessionattempts}{password} && $self->SanitizeData($opt{datamapping}{sessionattempts}{password},2)){ | ||||||
| 224 | $result++; $self->{datamapping}{sessionattempts}{password} = $opt{datamapping}{sessionattempts}{password}; | ||||||
| 225 | } | ||||||
| 226 | if(exists $opt{datamapping}{user}{table} && $self->SanitizeData($opt{datamapping}{user}{table},2)){ | ||||||
| 227 | $result++; $self->{datamapping}{user}{table} = $opt{datamapping}{user}{table}; | ||||||
| 228 | } | ||||||
| 229 | if(exists $opt{datamapping}{user}{userid} && $self->SanitizeData($opt{datamapping}{user}{userid},2)){ | ||||||
| 230 | $result++; $self->{datamapping}{user}{userid} = $opt{datamapping}{user}{userid}; | ||||||
| 231 | } | ||||||
| 232 | if(exists $opt{datamapping}{user}{password} && $self->SanitizeData($opt{datamapping}{user}{password},2)){ | ||||||
| 233 | $result++; $self->{datamapping}{user}{password} = $opt{datamapping}{user}{password}; | ||||||
| 234 | } | ||||||
| 235 | |||||||
| 236 | return $result; | ||||||
| 237 | } | ||||||
| 238 | sub Keygen { | ||||||
| 239 | # Creates a somewhat random key of $QueKeyLength size using numbers | ||||||
| 240 | # and uppercase and lowercase letters based on $complexity. | ||||||
| 241 | my($self, | ||||||
| 242 | $QueKeyLength, | ||||||
| 243 | $complexity)=@_; | ||||||
| 244 | my(@keys); | ||||||
| 245 | my($key) = ""; | ||||||
| 246 | $self->DebugAdd($PACKAGE."->Keygen()::Initialized",3); | ||||||
| 247 | |||||||
| 248 | if($QueKeyLength < 1 || $QueKeyLength > 128 ){ $QueKeyLength = 10; } | ||||||
| 249 | if($complexity == 1){ | ||||||
| 250 | @keys = ('A'..'Z'); | ||||||
| 251 | }elsif($complexity == 2){ | ||||||
| 252 | @keys = ('A'..'Z','0'..'9'); | ||||||
| 253 | }else{ | ||||||
| 254 | @keys = ('A'..'Z','a'..'z','0'..'9'); | ||||||
| 255 | } | ||||||
| 256 | for(my($a)=1; $a <= $QueKeyLength; $a++){ $key .= $keys[ int( rand($#keys)) ]; } | ||||||
| 257 | return $key; | ||||||
| 258 | } | ||||||
| 259 | sub SanitizeData{ | ||||||
| 260 | # do a test to see if there are any special characters | ||||||
| 261 | my($self,$data1,$opt) = @_; | ||||||
| 262 | my($result)=0; | ||||||
| 263 | my($data2) = $data1; | ||||||
| 264 | if($opt == 1){ # letters and numbers with underscore "_" | ||||||
| 265 | $data2 =~ s/[^a-zA-Z0-9_]//g; | ||||||
| 266 | }elsif($opt == 2){ # only letters and numbers | ||||||
| 267 | $data2 =~ s/[^a-zA-Z0-9]//g; | ||||||
| 268 | }elsif($opt == 3){ # positive or neg numbers | ||||||
| 269 | $data2 =~ s/[^0-9\-]//g; | ||||||
| 270 | }elsif($opt == 4){ # lower case letters numbers and dots + dashes | ||||||
| 271 | $data2 =~ s/[^a-z0-9\.\-]//g; | ||||||
| 272 | }else{ # positive numbers only | ||||||
| 273 | $data2 =~ s/[^0-9]//g; | ||||||
| 274 | } | ||||||
| 275 | if($data1 eq $data2){ | ||||||
| 276 | $result++;} | ||||||
| 277 | return $result | ||||||
| 278 | } | ||||||
| 279 | sub AutoAuth{ | ||||||
| 280 | # Automatically Authorize the user. | ||||||
| 281 | my($self,%opts) = @_; | ||||||
| 282 | my($result)=0; | ||||||
| 283 | $self->DebugAdd($PACKAGE."->AutoAuth()::Initialized",3); | ||||||
| 284 | |||||||
| 285 | if( defined($self->{user}) && defined($self->{hash})){ | ||||||
| 286 | $result = "Authorize"; | ||||||
| 287 | # $self->Authorize(%opts); | ||||||
| 288 | |||||||
| 289 | }elsif( defined($opts{cert}) ){ | ||||||
| 290 | $result = "Validate"; | ||||||
| 291 | # $self->Validate(%opts); | ||||||
| 292 | |||||||
| 293 | }else{ | ||||||
| 294 | $result = "Initialize"; | ||||||
| 295 | # $self->Initialize(%opts); | ||||||
| 296 | |||||||
| 297 | } | ||||||
| 298 | |||||||
| 299 | return $result; | ||||||
| 300 | } | ||||||
| 301 | sub UserAdd{ | ||||||
| 302 | # insert data into user table for login credentials | ||||||
| 303 | my($self, %opts) = @_; | ||||||
| 304 | my($redflag) = 0; | ||||||
| 305 | my($result) = 0; | ||||||
| 306 | my($hits) = 0; | ||||||
| 307 | $self->DebugAdd($PACKAGE."->UserAdd()::Initialized",3); | ||||||
| 308 | |||||||
| 309 | if(! $self->SanitizeData($opts{user},1)){$redflag++;} | ||||||
| 310 | |||||||
| 311 | # Check for user in the system | ||||||
| 312 | # We have two methods to sanitize databases with. | ||||||
| 313 | # We are using DBI::quote since we want to keep this extensible. | ||||||
| 314 | # on the front end after the DBH is created if it is a SQL database it will be the | ||||||
| 315 | # programmers responisbility to first parse it with method no. 1. We will try to | ||||||
| 316 | # keep things neat using method no. 2. | ||||||
| 317 | # 1. mysql_real_escape_string(); | ||||||
| 318 | # 2. $self->{dbh}->quote(); | ||||||
| 319 | my($sql)='SELECT COUNT(*) AS HITS FROM ' | ||||||
| 320 | . $self->{datamapping}{user}{table} | ||||||
| 321 | . ' WHERE ' | ||||||
| 322 | . $self->{datamapping}{user}{userid} | ||||||
| 323 | . ' = ' | ||||||
| 324 | . $self->{dbh}->quote( $opts{user} ); | ||||||
| 325 | |||||||
| 326 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 327 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->UserAdd()::Check",$sql, $!),1); | ||||||
| 328 | while (my $ref = $sth->fetchrow_hashref()){ | ||||||
| 329 | $hits = $ref->{'HITS'}; | ||||||
| 330 | } | ||||||
| 331 | $sth->finish(); | ||||||
| 332 | |||||||
| 333 | # if user is not in the system, add them, otherwise fail gracefully | ||||||
| 334 | if($hits == 0){ | ||||||
| 335 | # create user, they are not in the system | ||||||
| 336 | my($sql)='INSERT INTO ' | ||||||
| 337 | . $self->{datamapping}{user}{table} | ||||||
| 338 | . ' (' | ||||||
| 339 | . $self->{datamapping}{user}{userid} | ||||||
| 340 | . ', ' | ||||||
| 341 | . $self->{datamapping}{user}{password} | ||||||
| 342 | . ') VALUES (' | ||||||
| 343 | . ' ' | ||||||
| 344 | . $self->{dbh}->quote($opts{user}) | ||||||
| 345 | . ', ' | ||||||
| 346 | . $self->{dbh}->quote($opts{password}) | ||||||
| 347 | . ')'; | ||||||
| 348 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 349 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->UserAdd()::Add",$sql, $!),1); | ||||||
| 350 | $sth->finish(); | ||||||
| 351 | $result=2; | ||||||
| 352 | }else{ | ||||||
| 353 | # user in the system already | ||||||
| 354 | $self->DebugAdd($PACKAGE."->UserAdd()::User Exists{".$opts{user}."}",2); | ||||||
| 355 | $result=1; | ||||||
| 356 | } | ||||||
| 357 | return $result; | ||||||
| 358 | } | ||||||
| 359 | |||||||
| 360 | sub Initialize{ | ||||||
| 361 | my($self) = @_; | ||||||
| 362 | my($result) = 0; | ||||||
| 363 | my($cert); | ||||||
| 364 | my($ip) = $ENV{'REMOTE_ADDR'}; | ||||||
| 365 | my($stamp) = time(); | ||||||
| 366 | |||||||
| 367 | $self->DebugAdd($PACKAGE."->Initialize()::Initialized",3); | ||||||
| 368 | # insert data into sessions table to establish a login session | ||||||
| 369 | |||||||
| 370 | my($login) = 0; # toggles to 1 when successfull | ||||||
| 371 | my($max) = 0; # max number of trys for system safety when testing | ||||||
| 372 | my($hits) = 0; | ||||||
| 373 | |||||||
| 374 | while ($login <= 0 && $max < $self->{initcertretry}){ # make sure it is a unique entry | ||||||
| 375 | |||||||
| 376 | $cert = $self->Keygen(10,2); | ||||||
| 377 | |||||||
| 378 | my($sql)="SELECT COUNT(*) AS HITS FROM " | ||||||
| 379 | . $self->{datamapping}{session}{table} | ||||||
| 380 | . " WHERE " | ||||||
| 381 | . $self->{datamapping}{session}{ip} | ||||||
| 382 | . " = " | ||||||
| 383 | . $self->{dbh}->quote($ip) | ||||||
| 384 | . " AND " | ||||||
| 385 | . $self->{datamapping}{session}{cert} | ||||||
| 386 | . " = " | ||||||
| 387 | . $self->{dbh}->quote($cert); | ||||||
| 388 | |||||||
| 389 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 390 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->Initialize()",$sql, $!),1); | ||||||
| 391 | while (my $ref = $sth->fetchrow_hashref()){ | ||||||
| 392 | $hits = $ref->{'HITS'}; | ||||||
| 393 | } | ||||||
| 394 | $sth->finish(); | ||||||
| 395 | if($hits == 0){ | ||||||
| 396 | $login++; | ||||||
| 397 | }else{ | ||||||
| 398 | $max++; | ||||||
| 399 | $self->DebugAdd($self->SQL_Die("Initialize()::CreateCert::CertCollision",$sql,"Debug"),2); | ||||||
| 400 | } | ||||||
| 401 | } | ||||||
| 402 | if($hits == 0){ | ||||||
| 403 | # initialize the session transaction. | ||||||
| 404 | my($sql) = "INSERT INTO " | ||||||
| 405 | . $self->{datamapping}{session}{table} | ||||||
| 406 | . " (" | ||||||
| 407 | . $self->{datamapping}{session}{cert} | ||||||
| 408 | . "," | ||||||
| 409 | . $self->{datamapping}{session}{ip} | ||||||
| 410 | . "," | ||||||
| 411 | . $self->{datamapping}{session}{firstactive} | ||||||
| 412 | . "," | ||||||
| 413 | . $self->{datamapping}{session}{lastactive} | ||||||
| 414 | . ") VALUES(" | ||||||
| 415 | . $self->{dbh}->quote($cert) | ||||||
| 416 | . "," | ||||||
| 417 | . $self->{dbh}->quote($ip) | ||||||
| 418 | . "," | ||||||
| 419 | . $self->{dbh}->quote($stamp) | ||||||
| 420 | . "," | ||||||
| 421 | . $self->{dbh}->quote($stamp) | ||||||
| 422 | . ")"; | ||||||
| 423 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 424 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->Initialize()",$sql, $!),1); | ||||||
| 425 | $sth->finish(); | ||||||
| 426 | $result++; | ||||||
| 427 | } | ||||||
| 428 | # temp measure cert, ip, stamp should not be global var's | ||||||
| 429 | # $self->{cert} = $cert; | ||||||
| 430 | # $self->{ip} = $ip | ||||||
| 431 | # $self->{stamp} = $stamp | ||||||
| 432 | return (cert => $cert, | ||||||
| 433 | ip => $ip, | ||||||
| 434 | stamp => $stamp); | ||||||
| 435 | } | ||||||
| 436 | |||||||
| 437 | sub Validate{ | ||||||
| 438 | # ops{userid, cert, hash, pass} | ||||||
| 439 | # userid, cert, (hash || password) required | ||||||
| 440 | # + use only hash when self->compatmode = 0 | ||||||
| 441 | # + use only pass when self->compatmode = 1 | ||||||
| 442 | |||||||
| 443 | my($self,%opts) = @_; | ||||||
| 444 | $self->DebugAdd($PACKAGE."->Validate()::Initialized",3); | ||||||
| 445 | |||||||
| 446 | my($hash); | ||||||
| 447 | my($cert); | ||||||
| 448 | my($ip) = $ENV{'REMOTE_ADDR'}; | ||||||
| 449 | my($stamp) = time(); | ||||||
| 450 | my($result) = 0; | ||||||
| 451 | my($hits) = 0; | ||||||
| 452 | my($cookiedata)=""; | ||||||
| 453 | |||||||
| 454 | # TODO: Need to build validation for this | ||||||
| 455 | |||||||
| 456 | # Find all matching record for the primary key (Key,IP Address) | ||||||
| 457 | my(%SQL_SESSION); | ||||||
| 458 | my($sql) = "SELECT * FROM " | ||||||
| 459 | . $self->{datamapping}{session}{table} | ||||||
| 460 | . " WHERE " | ||||||
| 461 | . $self->{datamapping}{session}{cert} | ||||||
| 462 | . " = " | ||||||
| 463 | . $self->{dbh}->quote($opts{cert}) | ||||||
| 464 | . " AND " | ||||||
| 465 | . $self->{datamapping}{session}{ip} | ||||||
| 466 | . " = " | ||||||
| 467 | . $self->{dbh}->quote($ip) | ||||||
| 468 | . " LIMIT 0,1"; | ||||||
| 469 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 470 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->Validate()",$sql, $!),1); | ||||||
| 471 | while (my $ref = $sth->fetchrow_hashref()){ | ||||||
| 472 | $SQL_SESSION{firstactive} = $ref->{$self->{datamapping}{session}{firstactive}}; | ||||||
| 473 | } | ||||||
| 474 | $sth->finish(); | ||||||
| 475 | |||||||
| 476 | if( ! $SQL_SESSION{firstactive} ){ | ||||||
| 477 | # no: stop / log attempt; (Key,IP Address) not found in sessions. Log to sessionattempts | ||||||
| 478 | # ops{user, cert, hash, pass} | ||||||
| 479 | $self->DebugAdd($PACKAGE."->Validate()::Active(Key,IP Address) Not Found",2); | ||||||
| 480 | my($sql) = "INSERT INTO " | ||||||
| 481 | . $self->{datamapping}{sessionattempt}{table} | ||||||
| 482 | . " (" | ||||||
| 483 | . $self->{datamapping}{sessionattempt}{cert} | ||||||
| 484 | . "," | ||||||
| 485 | . $self->{datamapping}{sessionattempt}{ip} | ||||||
| 486 | . "," | ||||||
| 487 | . $self->{datamapping}{sessionattempt}{stamp} | ||||||
| 488 | . "," | ||||||
| 489 | . $self->{datamapping}{sessionattempt}{userid} | ||||||
| 490 | . "," | ||||||
| 491 | . $self->{datamapping}{sessionattempt}{hash} | ||||||
| 492 | . "," | ||||||
| 493 | . $self->{datamapping}{sessionattempt}{password} | ||||||
| 494 | . ") VALUES(" | ||||||
| 495 | . $self->{dbh}->quote($opts{cert}) | ||||||
| 496 | . "," | ||||||
| 497 | . $self->{dbh}->quote($ip) | ||||||
| 498 | . "," | ||||||
| 499 | . $self->{dbh}->quote($stamp) | ||||||
| 500 | . "," | ||||||
| 501 | . $self->{dbh}->quote($opts{userid}) | ||||||
| 502 | . "," | ||||||
| 503 | . $self->{dbh}->quote($opts{hash}) | ||||||
| 504 | . "," | ||||||
| 505 | . $self->{dbh}->quote($opts{password}) | ||||||
| 506 | . ")"; | ||||||
| 507 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 508 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->Initialize()",$sql, $!),1); | ||||||
| 509 | $sth->finish(); | ||||||
| 510 | }else{ | ||||||
| 511 | # Yes: continue | ||||||
| 512 | # Get the specified Username given from the client from the user table | ||||||
| 513 | my(%SQL_USER); | ||||||
| 514 | my($sql) = "SELECT * FROM " | ||||||
| 515 | . $self->{datamapping}{user}{table} | ||||||
| 516 | . " WHERE " | ||||||
| 517 | . $self->{datamapping}{user}{userid} | ||||||
| 518 | . " = " | ||||||
| 519 | . $self->{dbh}->quote($opts{userid}); | ||||||
| 520 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 521 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->Validate()",$sql, $!),1); | ||||||
| 522 | while (my $ref = $sth->fetchrow_hashref()){ | ||||||
| 523 | $SQL_USER{password} = $ref->{$self->{datamapping}{user}{password}}; | ||||||
| 524 | $SQL_USER{userid} = $ref->{$self->{datamapping}{user}{userid}}; | ||||||
| 525 | } | ||||||
| 526 | $sth->finish(); | ||||||
| 527 | |||||||
| 528 | # if(Is username Found?){Yes: continue}else{no: stop} | ||||||
| 529 | # -----TODO | ||||||
| 530 | |||||||
| 531 | # Create a secure 1 way Hash of the Username, Key, and Password | ||||||
| 532 | |||||||
| 533 | my($digestdata) = ($opts{userid} . $opts{cert} . $SQL_USER{password} . $SQL_SESSION{firstactive} ); | ||||||
| 534 | |||||||
| 535 | $hash = $self->DigestMake(data => $digestdata); | ||||||
| 536 | |||||||
| 537 | # if compat mode, ignore hash arg and build the hash without javascript | ||||||
| 538 | if($self->{compatmode} != 0){ | ||||||
| 539 | $self->DebugAdd($PACKAGE."->Validate()::CompatMode=1",3); | ||||||
| 540 | my($digestdata2) = ($opts{userid} . $opts{cert} . $opts{password} . $SQL_SESSION{firstactive}); | ||||||
| 541 | $opts{hash} = $self->DigestMake(data => $digestdata); | ||||||
| 542 | } | ||||||
| 543 | |||||||
| 544 | |||||||
| 545 | |||||||
| 546 | # Test the hashes against eachother on a time sensitive manner | ||||||
| 547 | if( $hash eq $opts{hash} && | ||||||
| 548 | $stamp <= ($SQL_SESSION{firstactive} + $self->{validation}) | ||||||
| 549 | ){ | ||||||
| 550 | |||||||
| 551 | # -----TODO | ||||||
| 552 | # this deletes anything, but we have to make it match our prefrences for the max number of user logins | ||||||
| 553 | # we do need some sort of cleanup though here.. this SQL statement needs revision | ||||||
| 554 | # my($sql) = "DELETE * FROM " | ||||||
| 555 | # . $self->{datamapping}{session}{table} | ||||||
| 556 | # . " WHERE NOT " | ||||||
| 557 | # . $self->{datamapping}{session}{userid} | ||||||
| 558 | # . " = " | ||||||
| 559 | # . $self->{dbh}->quote($opts{userid}) | ||||||
| 560 | # . " AND " | ||||||
| 561 | # . $self->{datamapping}{session}{cert} | ||||||
| 562 | # . " = " | ||||||
| 563 | # . $self->{dbh}->quote($opts{cert}) | ||||||
| 564 | # . " AND " | ||||||
| 565 | # . $self->{datamapping}{session}{ip} | ||||||
| 566 | # . " = " | ||||||
| 567 | # . $self->{dbh}->quote($ip); | ||||||
| 568 | # print $self->SQL_Die("Validate()",$sql,"Debug"); | ||||||
| 569 | # # $self->DebugAdd( $self->SQL_Die("Validate()",$sql,"Debug") ); | ||||||
| 570 | # my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 571 | # $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->Validate()",$sql, $!),1); | ||||||
| 572 | # $sth->finish(); | ||||||
| 573 | |||||||
| 574 | my($sql) = "UPDATE " | ||||||
| 575 | . $self->{datamapping}{session}{table} | ||||||
| 576 | . " SET " | ||||||
| 577 | . $self->{datamapping}{session}{lastactive} | ||||||
| 578 | . " = " | ||||||
| 579 | . $self->{dbh}->quote($stamp) | ||||||
| 580 | . ", " | ||||||
| 581 | . $self->{datamapping}{session}{hash} | ||||||
| 582 | . " = " | ||||||
| 583 | . $self->{dbh}->quote($hash) | ||||||
| 584 | . ", " | ||||||
| 585 | . $self->{datamapping}{session}{userid} | ||||||
| 586 | . " = " | ||||||
| 587 | . $self->{dbh}->quote($opts{userid}) | ||||||
| 588 | . " WHERE " | ||||||
| 589 | . $self->{datamapping}{session}{cert} | ||||||
| 590 | . " = " | ||||||
| 591 | . $self->{dbh}->quote($opts{cert}) | ||||||
| 592 | . " AND " | ||||||
| 593 | . $self->{datamapping}{session}{ip} | ||||||
| 594 | . " = " | ||||||
| 595 | . $self->{dbh}->quote($ip); | ||||||
| 596 | # $self->DebugAdd( $self->SQL_Die("Validate()",$sql,"Debug") ); | ||||||
| 597 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 598 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->Validate()",$sql, $!),1); | ||||||
| 599 | $sth->finish(); | ||||||
| 600 | # TODO: actions: | ||||||
| 601 | # delete all previous sessions for username (1 session per user) | ||||||
| 602 | |||||||
| 603 | $result = 1; | ||||||
| 604 | }else{ | ||||||
| 605 | # failed to validate | ||||||
| 606 | # print "'$hash' is ne '".$opts{hash}."' OR " .$stamp ." is not <= ". ($SQL_SESSION{firstactive} + $self->{validation})." "; |
||||||
| 607 | } | ||||||
| 608 | } | ||||||
| 609 | if($self->{usecookies}){ | ||||||
| 610 | $cookiedata = $self->CookieSet(data => "userid:".$opts{userid}.",hash:".$hash); | ||||||
| 611 | } | ||||||
| 612 | return (result => $result, | ||||||
| 613 | userid => $opts{userid}, | ||||||
| 614 | hash => $hash, | ||||||
| 615 | cookie => $cookiedata); | ||||||
| 616 | } | ||||||
| 617 | |||||||
| 618 | sub Authorize{ | ||||||
| 619 | my($self,%opts) = @_; | ||||||
| 620 | # ops{userid, hash} | ||||||
| 621 | |||||||
| 622 | my($ip) = $ENV{'REMOTE_ADDR'}; | ||||||
| 623 | my($stamp) = time(); | ||||||
| 624 | my($result) = 0; | ||||||
| 625 | my($hits) = 0; | ||||||
| 626 | $self->DebugAdd($PACKAGE."->Authorize()::Initialized",3); | ||||||
| 627 | |||||||
| 628 | # rules: | ||||||
| 629 | # CERT{hash} eq SQL.session{hash} | ||||||
| 630 | # CERT{userid} eq SQL.session{userid} | ||||||
| 631 | # Parsed{ip} eq SQL.session{ip} | ||||||
| 632 | # ($SQL_SESSION{firstactive} + $connection) = $stamp && | ||||||
| 633 | # ($SQL_SESSION{lastactive} + $idletime) >= $stamp | ||||||
| 634 | # actions: | ||||||
| 635 | # session{lastactive} = Parsed{time} | ||||||
| 636 | |||||||
| 637 | my(%SQL_SESSION); | ||||||
| 638 | my($sql)="SELECT * FROM " | ||||||
| 639 | . $self->{datamapping}{session}{table} | ||||||
| 640 | . " WHERE " | ||||||
| 641 | . $self->{datamapping}{session}{hash} | ||||||
| 642 | . " = " | ||||||
| 643 | . $self->{dbh}->quote($opts{hash}) | ||||||
| 644 | . " AND " | ||||||
| 645 | . $self->{datamapping}{session}{userid} | ||||||
| 646 | . " = " | ||||||
| 647 | . $self->{dbh}->quote($opts{userid}) | ||||||
| 648 | . " AND " | ||||||
| 649 | . $self->{datamapping}{session}{ip} | ||||||
| 650 | . " = " | ||||||
| 651 | . $self->{dbh}->quote($ip) | ||||||
| 652 | . " LIMIT 0,1"; | ||||||
| 653 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 654 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->Authorize()",$sql, $!),1); | ||||||
| 655 | while (my $ref = $sth->fetchrow_hashref()){ | ||||||
| 656 | $SQL_SESSION{firstactive} = $ref->{ $self->{datamapping}{session}{firstactive} }; | ||||||
| 657 | $SQL_SESSION{lastactive} = $ref->{ $self->{datamapping}{session}{lastactive} }; | ||||||
| 658 | } | ||||||
| 659 | $sth->finish(); | ||||||
| 660 | |||||||
| 661 | if( (($SQL_SESSION{firstactive} + $self->{connection}) >= $stamp) && | ||||||
| 662 | (($SQL_SESSION{lastactive} + $self->{idletime}) >= $stamp) | ||||||
| 663 | ){ | ||||||
| 664 | # Is the user session active valid? if it is update session table; | ||||||
| 665 | my($sql) = "UPDATE " | ||||||
| 666 | . $self->{datamapping}{session}{table} | ||||||
| 667 | . " SET " | ||||||
| 668 | . $self->{datamapping}{session}{lastactive} | ||||||
| 669 | . " = " | ||||||
| 670 | . $self->{dbh}->quote($stamp) | ||||||
| 671 | . " WHERE " | ||||||
| 672 | . $self->{datamapping}{session}{hash} | ||||||
| 673 | . " = " | ||||||
| 674 | . $self->{dbh}->quote($opts{hash}) | ||||||
| 675 | . " AND " | ||||||
| 676 | . $self->{datamapping}{session}{userid} | ||||||
| 677 | . " = " | ||||||
| 678 | . $self->{dbh}->quote($opts{userid}) | ||||||
| 679 | . " AND " | ||||||
| 680 | . $self->{datamapping}{session}{ip} | ||||||
| 681 | . " = " | ||||||
| 682 | . $self->{dbh}->quote($ip); | ||||||
| 683 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 684 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->Authorize()",$sql, $!),1); | ||||||
| 685 | $sth->finish(); | ||||||
| 686 | $result++; | ||||||
| 687 | }else{ | ||||||
| 688 | # Note the invalid attempt | ||||||
| 689 | } | ||||||
| 690 | return $result; | ||||||
| 691 | } | ||||||
| 692 | |||||||
| 693 | sub DigestMake{ | ||||||
| 694 | my($self,%opts) = @_; | ||||||
| 695 | $self->DebugAdd($PACKAGE."->Authorize()::DigestMake",3); | ||||||
| 696 | |||||||
| 697 | my($DIGEST); my($HASH); | ||||||
| 698 | |||||||
| 699 | if($self->{digest} eq "Digest::SHA1"){ | ||||||
| 700 | use Digest::SHA1; | ||||||
| 701 | $DIGEST = Digest::SHA1->new; | ||||||
| 702 | $DIGEST->add( $opts{data} ); | ||||||
| 703 | $HASH = $DIGEST->hexdigest; | ||||||
| 704 | }elsif($self->{digest} eq "MD5"){ | ||||||
| 705 | use Digest::MD5; | ||||||
| 706 | $DIGEST = Digest::MD5->new; | ||||||
| 707 | $DIGEST->add( $opts{data} ); | ||||||
| 708 | $HASH = $DIGEST->hexdigest; | ||||||
| 709 | }else{ | ||||||
| 710 | # Might do this way instead: | ||||||
| 711 | ################################################## | ||||||
| 712 | # use Package::Alias DIGESTNAME => $self->digest; | ||||||
| 713 | # use DIGESTNAME; | ||||||
| 714 | # $DIGEST = DIGESTNAME->new; | ||||||
| 715 | # $DIGEST->add($opts{data}); | ||||||
| 716 | # $HASH = $DIGEST->hexdigest; | ||||||
| 717 | ################################################## | ||||||
| 718 | |||||||
| 719 | eval ('use '.$self->digest); | ||||||
| 720 | eval ('$DIGEST = '.$self->digest.'->new'); | ||||||
| 721 | $DIGEST->add($opts{data}); | ||||||
| 722 | $HASH = $DIGEST->hexdigest; | ||||||
| 723 | } | ||||||
| 724 | return $HASH; | ||||||
| 725 | } | ||||||
| 726 | |||||||
| 727 | sub DeleteExpiredSessions { | ||||||
| 728 | # scrubs any expired sessions | ||||||
| 729 | my($self,%opts) = @_; | ||||||
| 730 | my($result) = 0; | ||||||
| 731 | |||||||
| 732 | return $result; | ||||||
| 733 | } | ||||||
| 734 | |||||||
| 735 | sub TableMake{ | ||||||
| 736 | my($self, %opts) = @_; | ||||||
| 737 | my($result) = 0; | ||||||
| 738 | $self->DebugAdd($PACKAGE."->TableMake()::Initialized",3); | ||||||
| 739 | |||||||
| 740 | if(defined($opts{'table'}) && (lc($opts{'table'}) eq 'all'|| lc($opts{'table'}) eq 'session')){ | ||||||
| 741 | $self->DebugAdd($PACKAGE."->TableMake()::CreatingTable::Session",3); | ||||||
| 742 | my($sql)= qq^CREATE TABLE IF NOT EXISTS ^ . $self->{datamapping}{session}{table} | ||||||
| 743 | . qq^ (^ . $self->{datamapping}{session}{ip} | ||||||
| 744 | . qq^ VARCHAR(15) NOT NULL, ^ . $self->{datamapping}{session}{cert} | ||||||
| 745 | . qq^ VARCHAR(10) NOT NULL, ^ . $self->{datamapping}{session}{hash} | ||||||
| 746 | . qq^ VARCHAR(45), ^ . $self->{datamapping}{session}{userid} | ||||||
| 747 | . qq^ VARCHAR(45), ^ . $self->{datamapping}{session}{firstactive} | ||||||
| 748 | . qq^ VARCHAR(45), ^ . $self->{datamapping}{session}{lastactive} | ||||||
| 749 | . qq^ VARCHAR(45), PRIMARY KEY(^ . $self->{datamapping}{session}{ip} | ||||||
| 750 | . qq^, ^ . $self->{datamapping}{session}{cert} | ||||||
| 751 | . qq^))^; | ||||||
| 752 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 753 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->TableMake(table => '".$opts{'table'}."')::Create Table::Session::Execute",$sql, $!),1); | ||||||
| 754 | $sth->finish(); | ||||||
| 755 | $result++; | ||||||
| 756 | } | ||||||
| 757 | |||||||
| 758 | if(defined($opts{'table'}) && (lc($opts{'table'}) eq 'all'|| lc($opts{'table'}) eq 'sessionattempts')){ | ||||||
| 759 | $self->DebugAdd($PACKAGE."->TableMake()::CreatingTable::SessionAttempts",3); | ||||||
| 760 | my($sql)= qq^CREATE TABLE IF NOT EXISTS ^.$self->{datamapping}{sessionattempts}{table} | ||||||
| 761 | .qq^ (^.$self->{datamapping}{sessionattempts}{ip} | ||||||
| 762 | .qq^ varchar(15) NOT NULL, ^.$self->{datamapping}{sessionattempts}{stamp} | ||||||
| 763 | .qq^ varchar(10) NOT NULL, ^.$self->{datamapping}{sessionattempts}{hash} | ||||||
| 764 | .qq^ varchar(45) default NULL, ^.$self->{datamapping}{sessionattempts}{userid} | ||||||
| 765 | .qq^ varchar(45) default NULL, ^.$self->{datamapping}{sessionattempts}{cert} | ||||||
| 766 | .qq^ varchar(45) default NULL, ^.$self->{datamapping}{sessionattempts}{password} | ||||||
| 767 | .qq^ varchar(45) default NULL, PRIMARY KEY(^.$self->{datamapping}{sessionattempts}{ip} | ||||||
| 768 | .qq^, ^.$self->{datamapping}{sessionattempts}{stamp} | ||||||
| 769 | .qq^))^; | ||||||
| 770 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 771 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->TableMake(table => '".$opts{'table'}."')::Create Table::SessionAttempts::Execute",$sql, $!),1); | ||||||
| 772 | $sth->finish(); | ||||||
| 773 | $result++; | ||||||
| 774 | } | ||||||
| 775 | |||||||
| 776 | if(defined($opts{'table'}) && (lc($opts{'table'}) eq 'all'|| lc($opts{'table'}) eq 'sessionlocks')){ | ||||||
| 777 | $self->DebugAdd($PACKAGE."->TableMake()::CreatingTable::SessionLocks",3); | ||||||
| 778 | my($sql)= qq^CREATE TABLE IF NOT EXISTS ^.$self->{datamapping}{sessionlocks}{table} | ||||||
| 779 | .qq^ (^.$self->{datamapping}{sessionlocks}{ip} | ||||||
| 780 | .qq^ varchar(15) NOT NULL, ^.$self->{datamapping}{sessionlocks}{stamp} | ||||||
| 781 | .qq^ varchar(10) NOT NULL, ^.$self->{datamapping}{sessionlocks}{hash} | ||||||
| 782 | .qq^ varchar(45) default NULL, ^.$self->{datamapping}{sessionlocks}{userid} | ||||||
| 783 | .qq^ varchar(45) default NULL, ^.$self->{datamapping}{sessionlocks}{cert} | ||||||
| 784 | .qq^ varchar(45) default NULL, PRIMARY KEY(^.$self->{datamapping}{sessionlocks}{ip} | ||||||
| 785 | .qq^,^.$self->{datamapping}{sessionlocks}{stamp} | ||||||
| 786 | .qq^))^; | ||||||
| 787 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 788 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->TableMake(table => '".$opts{'table'}."')::Create Table::SessionLocks::Execute",$sql, $!),1); | ||||||
| 789 | $sth->finish(); | ||||||
| 790 | $result++; | ||||||
| 791 | } | ||||||
| 792 | |||||||
| 793 | if(defined($opts{'table'}) && (lc($opts{'table'}) eq 'all'|| lc($opts{'table'}) eq 'user')){ | ||||||
| 794 | $self->DebugAdd($PACKAGE."->TableMake()::CreatingTable::User",3); | ||||||
| 795 | my($sql)= qq^CREATE TABLE IF NOT EXISTS ^.$self->{datamapping}{user}{table} | ||||||
| 796 | .qq^ (^.$self->{datamapping}{user}{userid} | ||||||
| 797 | .qq^ varchar(50) NOT NULL,^.$self->{datamapping}{user}{password} | ||||||
| 798 | .qq^ varchar(50) default NULL, PRIMARY KEY(^.$self->{datamapping}{user}{userid} | ||||||
| 799 | .qq^))^; | ||||||
| 800 | my($sth) = $self->{dbh}->prepare($sql); | ||||||
| 801 | $sth->execute() or $self->DebugShow($self->SQL_Die("Auth->TableMake(table => '".$opts{'table'}."')::Create Table::User::Execute",$sql, $!),1); | ||||||
| 802 | $sth->finish(); | ||||||
| 803 | $result++; | ||||||
| 804 | } | ||||||
| 805 | return $result; # Number of SQL statements processed successfully. | ||||||
| 806 | } | ||||||
| 807 | |||||||
| 808 | sub SQL_Die{ | ||||||
| 809 | # Deguging tool: Helps neatly print SQL statements out when module for debug messages. | ||||||
| 810 | my($self, $subroutine, $sql, $err) = @_; | ||||||
| 811 | my(@keys)=("FROM","WHERE","VALUES","SET","OR","AND","LIMIT","ORDER","BETWEEN","IN", "AS", "UNION", "INTO", "IF"); | ||||||
| 812 | my($cnt)= "\n"; |
||||||
| 813 | for(my($a) = 0; $a <= $#keys; $a++){ | ||||||
| 814 | my($b) = " " . $keys[$a] . " "; | ||||||
| 815 | my($c) = "\n" . $b; | ||||||
| 816 | $sql =~ s/$b/$c/gi; | ||||||
| 817 | } | ||||||
| 818 | $sql =~ s/, /,\n /g; | ||||||
| 819 | return ("\n \nCan not execute SQL statement $PACKAGE->". $subroutine ."". $cnt . $sql .";\n$err\n ");
|
||||||
| 820 | } | ||||||
| 821 | sub DebugAdd{ | ||||||
| 822 | # Deguging tool: Appends debugging information to the main module. | ||||||
| 823 | my($self,$data,$level) = @_; | ||||||
| 824 | if($self->{debug} >= $level){ | ||||||
| 825 | my($leveltext)=""; | ||||||
| 826 | if($level == 1){ | ||||||
| 827 | $leveltext = "Error"; | ||||||
| 828 | }elsif($level == 2){ | ||||||
| 829 | $leveltext = "Warning"; | ||||||
| 830 | }elsif($level == 3){ | ||||||
| 831 | $leveltext = "Infomation"; | ||||||
| 832 | }else{ | ||||||
| 833 | $leveltext = "Unknown"; | ||||||
| 834 | } | ||||||
| 835 | $self->{debuginfo} .= " ".$leveltext.": Time: " . localtime() . " [" . time() . "] " . $data; |
||||||
| 836 | } | ||||||
| 837 | } | ||||||
| 838 | sub DebugShow{ | ||||||
| 839 | my($self,$data,$level) = @_; | ||||||
| 840 | $self->DebugAdd($data,$level); | ||||||
| 841 | if($self->{debug} > 0){ | ||||||
| 842 | print $self->{debuginfo}; | ||||||
| 843 | } | ||||||
| 844 | } | ||||||
| 845 | |||||||
| 846 | sub CookieGet { | ||||||
| 847 | # move cookies to a hash | ||||||
| 848 | my($self,%opts) = @_; | ||||||
| 849 | $self->DebugAdd($PACKAGE."->CookieGet()::Initialized",3); | ||||||
| 850 | my(%result); | ||||||
| 851 | my($nm) = ( defined($opts{name}) )? $opts{name} : $self->{cookiename}; | ||||||
| 852 | my($query) = new CGI; | ||||||
| 853 | my(@cookies) = split(/;/, $query->cookie($nm)); | ||||||
| 854 | |||||||
| 855 | for (my($a)=0; $a <= $#cookies; $a++){ | ||||||
| 856 | my @pairs = split(/,/,$cookies[$a]); | ||||||
| 857 | for (my($b)=0; $b <= $#pairs; $b++){ | ||||||
| 858 | my($n,$v) = split(/:/, $pairs[$b]) ; | ||||||
| 859 | $result{$n} = $v; | ||||||
| 860 | } | ||||||
| 861 | last; | ||||||
| 862 | } | ||||||
| 863 | return (%result); | ||||||
| 864 | } | ||||||
| 865 | |||||||
| 866 | sub CookieSet { | ||||||
| 867 | # move data to a cookie | ||||||
| 868 | my($self,%opts) = @_; | ||||||
| 869 | $self->DebugAdd($PACKAGE."->CookieWrite()::Initialized",3); | ||||||
| 870 | |||||||
| 871 | my($query) = new CGI; | ||||||
| 872 | my($nm) = ( defined($opts{name}) )? $opts{name} : $self->{cookiename}; | ||||||
| 873 | my($domain)= ( defined($opts{domain}) )? $opts{domain} : $self->{domain}; | ||||||
| 874 | my($path) = ( defined($opts{path}) )? $opts{path} : "/"; | ||||||
| 875 | my($gmt) = ( defined($opts{gmt}) )? $opts{gmt} : gmtime(time() + $self->{idletime})." GMT;"; | ||||||
| 876 | my($cookie)= $query->cookie(-domain => $domain, | ||||||
| 877 | -name => $nm, | ||||||
| 878 | -value => $opts{data}, | ||||||
| 879 | -expires => $gmt, | ||||||
| 880 | -path => $path); | ||||||
| 881 | |||||||
| 882 | print "Set-Cookie: $cookie\n"; | ||||||
| 883 | $self->DebugAdd($PACKAGE."->CookieWrite()::Cookie Written".$cookie,3); | ||||||
| 884 | |||||||
| 885 | return $cookie; | ||||||
| 886 | } | ||||||
| 887 | |||||||
| 888 | sub WriteScript{ | ||||||
| 889 | # print a javascript | ||||||
| 890 | my($self,$script) = @_; | ||||||
| 891 | if($script eq undef){ $script = $self->JS_Digest(); } | ||||||
| 892 | my($result)= qq^\n\n^; | ||||||
| 893 | return $result; | ||||||
| 894 | } | ||||||
| 895 | |||||||
| 896 | sub JS_Digest{ | ||||||
| 897 | my($self,%opts) = @_; | ||||||
| 898 | |||||||
| 899 | if($self->{digest} eq "MD5"){ | ||||||
| 900 | |||||||
| 901 | return <<"ENDTAG" | ||||||
| 902 | /* | ||||||
| 903 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message | ||||||
| 904 | * Digest Algorithm, as defined in RFC 1321. | ||||||
| 905 | * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. | ||||||
| 906 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet | ||||||
| 907 | * Distributed under the BSD License | ||||||
| 908 | * See http://pajhome.org.uk/crypt/md5 for more info. | ||||||
| 909 | */ | ||||||
| 910 | |||||||
| 911 | /* | ||||||
| 912 | * Configurable variables. You may need to tweak these to be compatible with | ||||||
| 913 | * the server-side, but the defaults work in most cases. | ||||||
| 914 | */ | ||||||
| 915 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ | ||||||
| 916 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ | ||||||
| 917 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ | ||||||
| 918 | |||||||
| 919 | /* | ||||||
| 920 | * These are the functions you will usually want to call | ||||||
| 921 | * They take string arguments and return either hex or base-64 encoded strings | ||||||
| 922 | */ | ||||||
| 923 | function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));} | ||||||
| 924 | function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));} | ||||||
| 925 | function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));} | ||||||
| 926 | function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); } | ||||||
| 927 | function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); } | ||||||
| 928 | function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); } | ||||||
| 929 | |||||||
| 930 | /* | ||||||
| 931 | * Perform a simple self-test to see if the VM is working | ||||||
| 932 | */ | ||||||
| 933 | function md5_vm_test() | ||||||
| 934 | { | ||||||
| 935 | return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; | ||||||
| 936 | } | ||||||
| 937 | |||||||
| 938 | /* | ||||||
| 939 | * Calculate the MD5 of an array of little-endian words, and a bit length | ||||||
| 940 | */ | ||||||
| 941 | function core_md5(x, len) | ||||||
| 942 | { | ||||||
| 943 | /* append padding */ | ||||||
| 944 | x[len >> 5] |= 0x80 << ((len) % 32); | ||||||
| 945 | x[(((len + 64) >>> 9) << 4) + 14] = len; | ||||||
| 946 | |||||||
| 947 | var a = 1732584193; | ||||||
| 948 | var b = -271733879; | ||||||
| 949 | var c = -1732584194; | ||||||
| 950 | var d = 271733878; | ||||||
| 951 | |||||||
| 952 | for(var i = 0; i < x.length; i += 16) | ||||||
| 953 | { | ||||||
| 954 | var olda = a; | ||||||
| 955 | var oldb = b; | ||||||
| 956 | var oldc = c; | ||||||
| 957 | var oldd = d; | ||||||
| 958 | |||||||
| 959 | a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); | ||||||
| 960 | d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); | ||||||
| 961 | c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); | ||||||
| 962 | b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); | ||||||
| 963 | a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); | ||||||
| 964 | d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); | ||||||
| 965 | c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); | ||||||
| 966 | b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); | ||||||
| 967 | a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); | ||||||
| 968 | d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); | ||||||
| 969 | c = md5_ff(c, d, a, b, x[i+10], 17, -42063); | ||||||
| 970 | b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); | ||||||
| 971 | a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); | ||||||
| 972 | d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); | ||||||
| 973 | c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); | ||||||
| 974 | b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); | ||||||
| 975 | |||||||
| 976 | a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); | ||||||
| 977 | d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); | ||||||
| 978 | c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); | ||||||
| 979 | b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); | ||||||
| 980 | a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); | ||||||
| 981 | d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); | ||||||
| 982 | c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); | ||||||
| 983 | b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); | ||||||
| 984 | a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); | ||||||
| 985 | d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); | ||||||
| 986 | c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); | ||||||
| 987 | b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); | ||||||
| 988 | a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); | ||||||
| 989 | d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); | ||||||
| 990 | c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); | ||||||
| 991 | b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); | ||||||
| 992 | |||||||
| 993 | a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); | ||||||
| 994 | d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); | ||||||
| 995 | c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); | ||||||
| 996 | b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); | ||||||
| 997 | a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); | ||||||
| 998 | d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); | ||||||
| 999 | c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); | ||||||
| 1000 | b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); | ||||||
| 1001 | a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); | ||||||
| 1002 | d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); | ||||||
| 1003 | c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); | ||||||
| 1004 | b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); | ||||||
| 1005 | a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); | ||||||
| 1006 | d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); | ||||||
| 1007 | c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); | ||||||
| 1008 | b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); | ||||||
| 1009 | |||||||
| 1010 | a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); | ||||||
| 1011 | d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); | ||||||
| 1012 | c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); | ||||||
| 1013 | b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); | ||||||
| 1014 | a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); | ||||||
| 1015 | d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); | ||||||
| 1016 | c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); | ||||||
| 1017 | b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); | ||||||
| 1018 | a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); | ||||||
| 1019 | d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); | ||||||
| 1020 | c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); | ||||||
| 1021 | b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); | ||||||
| 1022 | a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); | ||||||
| 1023 | d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); | ||||||
| 1024 | c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); | ||||||
| 1025 | b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); | ||||||
| 1026 | |||||||
| 1027 | a = safe_add(a, olda); | ||||||
| 1028 | b = safe_add(b, oldb); | ||||||
| 1029 | c = safe_add(c, oldc); | ||||||
| 1030 | d = safe_add(d, oldd); | ||||||
| 1031 | } | ||||||
| 1032 | return Array(a, b, c, d); | ||||||
| 1033 | |||||||
| 1034 | } | ||||||
| 1035 | |||||||
| 1036 | /* | ||||||
| 1037 | * These functions implement the four basic operations the algorithm uses. | ||||||
| 1038 | */ | ||||||
| 1039 | function md5_cmn(q, a, b, x, s, t) | ||||||
| 1040 | { | ||||||
| 1041 | return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); | ||||||
| 1042 | } | ||||||
| 1043 | function md5_ff(a, b, c, d, x, s, t) | ||||||
| 1044 | { | ||||||
| 1045 | return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); | ||||||
| 1046 | } | ||||||
| 1047 | function md5_gg(a, b, c, d, x, s, t) | ||||||
| 1048 | { | ||||||
| 1049 | return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); | ||||||
| 1050 | } | ||||||
| 1051 | function md5_hh(a, b, c, d, x, s, t) | ||||||
| 1052 | { | ||||||
| 1053 | return md5_cmn(b ^ c ^ d, a, b, x, s, t); | ||||||
| 1054 | } | ||||||
| 1055 | function md5_ii(a, b, c, d, x, s, t) | ||||||
| 1056 | { | ||||||
| 1057 | return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); | ||||||
| 1058 | } | ||||||
| 1059 | |||||||
| 1060 | /* | ||||||
| 1061 | * Calculate the HMAC-MD5, of a key and some data | ||||||
| 1062 | */ | ||||||
| 1063 | function core_hmac_md5(key, data) | ||||||
| 1064 | { | ||||||
| 1065 | var bkey = str2binl(key); | ||||||
| 1066 | if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); | ||||||
| 1067 | |||||||
| 1068 | var ipad = Array(16), opad = Array(16); | ||||||
| 1069 | for(var i = 0; i < 16; i++) | ||||||
| 1070 | { | ||||||
| 1071 | ipad[i] = bkey[i] ^ 0x36363636; | ||||||
| 1072 | opad[i] = bkey[i] ^ 0x5C5C5C5C; | ||||||
| 1073 | } | ||||||
| 1074 | |||||||
| 1075 | var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); | ||||||
| 1076 | return core_md5(opad.concat(hash), 512 + 128); | ||||||
| 1077 | } | ||||||
| 1078 | |||||||
| 1079 | /* | ||||||
| 1080 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally | ||||||
| 1081 | * to work around bugs in some JS interpreters. | ||||||
| 1082 | */ | ||||||
| 1083 | function safe_add(x, y) | ||||||
| 1084 | { | ||||||
| 1085 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); | ||||||
| 1086 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); | ||||||
| 1087 | return (msw << 16) | (lsw & 0xFFFF); | ||||||
| 1088 | } | ||||||
| 1089 | |||||||
| 1090 | /* | ||||||
| 1091 | * Bitwise rotate a 32-bit number to the left. | ||||||
| 1092 | */ | ||||||
| 1093 | function bit_rol(num, cnt) | ||||||
| 1094 | { | ||||||
| 1095 | return (num << cnt) | (num >>> (32 - cnt)); | ||||||
| 1096 | } | ||||||
| 1097 | |||||||
| 1098 | /* | ||||||
| 1099 | * Convert a string to an array of little-endian words | ||||||
| 1100 | * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. | ||||||
| 1101 | */ | ||||||
| 1102 | function str2binl(str) | ||||||
| 1103 | { | ||||||
| 1104 | var bin = Array(); | ||||||
| 1105 | var mask = (1 << chrsz) - 1; | ||||||
| 1106 | for(var i = 0; i < str.length * chrsz; i += chrsz) | ||||||
| 1107 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); | ||||||
| 1108 | return bin; | ||||||
| 1109 | } | ||||||
| 1110 | |||||||
| 1111 | /* | ||||||
| 1112 | * Convert an array of little-endian words to a string | ||||||
| 1113 | */ | ||||||
| 1114 | function binl2str(bin) | ||||||
| 1115 | { | ||||||
| 1116 | var str = ""; | ||||||
| 1117 | var mask = (1 << chrsz) - 1; | ||||||
| 1118 | for(var i = 0; i < bin.length * 32; i += chrsz) | ||||||
| 1119 | str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); | ||||||
| 1120 | return str; | ||||||
| 1121 | } | ||||||
| 1122 | |||||||
| 1123 | /* | ||||||
| 1124 | * Convert an array of little-endian words to a hex string. | ||||||
| 1125 | */ | ||||||
| 1126 | function binl2hex(binarray) | ||||||
| 1127 | { | ||||||
| 1128 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; | ||||||
| 1129 | var str = ""; | ||||||
| 1130 | for(var i = 0; i < binarray.length * 4; i++) | ||||||
| 1131 | { | ||||||
| 1132 | str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + | ||||||
| 1133 | hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF); | ||||||
| 1134 | } | ||||||
| 1135 | return str; | ||||||
| 1136 | } | ||||||
| 1137 | |||||||
| 1138 | /* | ||||||
| 1139 | * Convert an array of little-endian words to a base-64 string | ||||||
| 1140 | */ | ||||||
| 1141 | function binl2b64(binarray) | ||||||
| 1142 | { | ||||||
| 1143 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||||||
| 1144 | var str = ""; | ||||||
| 1145 | for(var i = 0; i < binarray.length * 4; i += 3) | ||||||
| 1146 | { | ||||||
| 1147 | var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) | ||||||
| 1148 | | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) | ||||||
| 1149 | | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); | ||||||
| 1150 | for(var j = 0; j < 4; j++) | ||||||
| 1151 | { | ||||||
| 1152 | if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; | ||||||
| 1153 | else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); | ||||||
| 1154 | } | ||||||
| 1155 | } | ||||||
| 1156 | return str; | ||||||
| 1157 | } | ||||||
| 1158 | ENDTAG | ||||||
| 1159 | |||||||
| 1160 | #################################################################### | ||||||
| 1161 | }else{ # $self->{digest} eq "Digest::SHA1" | ||||||
| 1162 | #################################################################### | ||||||
| 1163 | |||||||
| 1164 | return <<"ENDTAG" | ||||||
| 1165 | /* | ||||||
| 1166 | * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined | ||||||
| 1167 | * in FIPS PUB 180-1 | ||||||
| 1168 | * Version 2.1a Copyright Paul Johnston 2000 - 2002. | ||||||
| 1169 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet | ||||||
| 1170 | * Distributed under the BSD License | ||||||
| 1171 | * See http://pajhome.org.uk/crypt/md5 for details. | ||||||
| 1172 | */ | ||||||
| 1173 | |||||||
| 1174 | /* | ||||||
| 1175 | * Configurable variables. You may need to tweak these to be compatible with | ||||||
| 1176 | * the server-side, but the defaults work in most cases. | ||||||
| 1177 | */ | ||||||
| 1178 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ | ||||||
| 1179 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ | ||||||
| 1180 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ | ||||||
| 1181 | |||||||
| 1182 | /* | ||||||
| 1183 | * These are the functions you will usually want to call | ||||||
| 1184 | * They take string arguments and return either hex or base-64 encoded strings | ||||||
| 1185 | */ | ||||||
| 1186 | function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} | ||||||
| 1187 | function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} | ||||||
| 1188 | function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} | ||||||
| 1189 | function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} | ||||||
| 1190 | function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} | ||||||
| 1191 | function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} | ||||||
| 1192 | |||||||
| 1193 | /* | ||||||
| 1194 | * Perform a simple self-test to see if the VM is working | ||||||
| 1195 | */ | ||||||
| 1196 | function sha1_vm_test() | ||||||
| 1197 | { | ||||||
| 1198 | return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; | ||||||
| 1199 | } | ||||||
| 1200 | |||||||
| 1201 | /* | ||||||
| 1202 | * Calculate the SHA-1 of an array of big-endian words, and a bit length | ||||||
| 1203 | */ | ||||||
| 1204 | function core_sha1(x, len) | ||||||
| 1205 | { | ||||||
| 1206 | /* append padding */ | ||||||
| 1207 | x[len >> 5] |= 0x80 << (24 - len % 32); | ||||||
| 1208 | x[((len + 64 >> 9) << 4) + 15] = len; | ||||||
| 1209 | |||||||
| 1210 | var w = Array(80); | ||||||
| 1211 | var a = 1732584193; | ||||||
| 1212 | var b = -271733879; | ||||||
| 1213 | var c = -1732584194; | ||||||
| 1214 | var d = 271733878; | ||||||
| 1215 | var e = -1009589776; | ||||||
| 1216 | |||||||
| 1217 | for(var i = 0; i < x.length; i += 16) | ||||||
| 1218 | { | ||||||
| 1219 | var olda = a; | ||||||
| 1220 | var oldb = b; | ||||||
| 1221 | var oldc = c; | ||||||
| 1222 | var oldd = d; | ||||||
| 1223 | var olde = e; | ||||||
| 1224 | |||||||
| 1225 | for(var j = 0; j < 80; j++) | ||||||
| 1226 | { | ||||||
| 1227 | if(j < 16) w[j] = x[i + j]; | ||||||
| 1228 | else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); | ||||||
| 1229 | var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), | ||||||
| 1230 | safe_add(safe_add(e, w[j]), sha1_kt(j))); | ||||||
| 1231 | e = d; | ||||||
| 1232 | d = c; | ||||||
| 1233 | c = rol(b, 30); | ||||||
| 1234 | b = a; | ||||||
| 1235 | a = t; | ||||||
| 1236 | } | ||||||
| 1237 | |||||||
| 1238 | a = safe_add(a, olda); | ||||||
| 1239 | b = safe_add(b, oldb); | ||||||
| 1240 | c = safe_add(c, oldc); | ||||||
| 1241 | d = safe_add(d, oldd); | ||||||
| 1242 | e = safe_add(e, olde); | ||||||
| 1243 | } | ||||||
| 1244 | return Array(a, b, c, d, e); | ||||||
| 1245 | |||||||
| 1246 | } | ||||||
| 1247 | |||||||
| 1248 | /* | ||||||
| 1249 | * Perform the appropriate triplet combination function for the current | ||||||
| 1250 | * iteration | ||||||
| 1251 | */ | ||||||
| 1252 | function sha1_ft(t, b, c, d) | ||||||
| 1253 | { | ||||||
| 1254 | if(t < 20) return (b & c) | ((~b) & d); | ||||||
| 1255 | if(t < 40) return b ^ c ^ d; | ||||||
| 1256 | if(t < 60) return (b & c) | (b & d) | (c & d); | ||||||
| 1257 | return b ^ c ^ d; | ||||||
| 1258 | } | ||||||
| 1259 | |||||||
| 1260 | /* | ||||||
| 1261 | * Determine the appropriate additive constant for the current iteration | ||||||
| 1262 | */ | ||||||
| 1263 | function sha1_kt(t) | ||||||
| 1264 | { | ||||||
| 1265 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : | ||||||
| 1266 | (t < 60) ? -1894007588 : -899497514; | ||||||
| 1267 | } | ||||||
| 1268 | |||||||
| 1269 | /* | ||||||
| 1270 | * Calculate the HMAC-SHA1 of a key and some data | ||||||
| 1271 | */ | ||||||
| 1272 | function core_hmac_sha1(key, data) | ||||||
| 1273 | { | ||||||
| 1274 | var bkey = str2binb(key); | ||||||
| 1275 | if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); | ||||||
| 1276 | |||||||
| 1277 | var ipad = Array(16), opad = Array(16); | ||||||
| 1278 | for(var i = 0; i < 16; i++) | ||||||
| 1279 | { | ||||||
| 1280 | ipad[i] = bkey[i] ^ 0x36363636; | ||||||
| 1281 | opad[i] = bkey[i] ^ 0x5C5C5C5C; | ||||||
| 1282 | } | ||||||
| 1283 | |||||||
| 1284 | var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); | ||||||
| 1285 | return core_sha1(opad.concat(hash), 512 + 160); | ||||||
| 1286 | } | ||||||
| 1287 | |||||||
| 1288 | /* | ||||||
| 1289 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally | ||||||
| 1290 | * to work around bugs in some JS interpreters. | ||||||
| 1291 | */ | ||||||
| 1292 | function safe_add(x, y) | ||||||
| 1293 | { | ||||||
| 1294 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); | ||||||
| 1295 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); | ||||||
| 1296 | return (msw << 16) | (lsw & 0xFFFF); | ||||||
| 1297 | } | ||||||
| 1298 | |||||||
| 1299 | /* | ||||||
| 1300 | * Bitwise rotate a 32-bit number to the left. | ||||||
| 1301 | */ | ||||||
| 1302 | function rol(num, cnt) | ||||||
| 1303 | { | ||||||
| 1304 | return (num << cnt) | (num >>> (32 - cnt)); | ||||||
| 1305 | } | ||||||
| 1306 | |||||||
| 1307 | /* | ||||||
| 1308 | * Convert an 8-bit or 16-bit string to an array of big-endian words | ||||||
| 1309 | * In 8-bit function, characters >255 have their hi-byte silently ignored. | ||||||
| 1310 | */ | ||||||
| 1311 | function str2binb(str) | ||||||
| 1312 | { | ||||||
| 1313 | var bin = Array(); | ||||||
| 1314 | var mask = (1 << chrsz) - 1; | ||||||
| 1315 | for(var i = 0; i < str.length * chrsz; i += chrsz) | ||||||
| 1316 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); | ||||||
| 1317 | return bin; | ||||||
| 1318 | } | ||||||
| 1319 | |||||||
| 1320 | /* | ||||||
| 1321 | * Convert an array of big-endian words to a string | ||||||
| 1322 | */ | ||||||
| 1323 | function binb2str(bin) | ||||||
| 1324 | { | ||||||
| 1325 | var str = ""; | ||||||
| 1326 | var mask = (1 << chrsz) - 1; | ||||||
| 1327 | for(var i = 0; i < bin.length * 32; i += chrsz) | ||||||
| 1328 | str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); | ||||||
| 1329 | return str; | ||||||
| 1330 | } | ||||||
| 1331 | |||||||
| 1332 | /* | ||||||
| 1333 | * Convert an array of big-endian words to a hex string. | ||||||
| 1334 | */ | ||||||
| 1335 | function binb2hex(binarray) | ||||||
| 1336 | { | ||||||
| 1337 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; | ||||||
| 1338 | var str = ""; | ||||||
| 1339 | for(var i = 0; i < binarray.length * 4; i++) | ||||||
| 1340 | { | ||||||
| 1341 | str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + | ||||||
| 1342 | hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); | ||||||
| 1343 | } | ||||||
| 1344 | return str; | ||||||
| 1345 | } | ||||||
| 1346 | |||||||
| 1347 | /* | ||||||
| 1348 | * Convert an array of big-endian words to a base-64 string | ||||||
| 1349 | */ | ||||||
| 1350 | function binb2b64(binarray) | ||||||
| 1351 | { | ||||||
| 1352 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||||||
| 1353 | var str = ""; | ||||||
| 1354 | for(var i = 0; i < binarray.length * 4; i += 3) | ||||||
| 1355 | { | ||||||
| 1356 | var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) | ||||||
| 1357 | | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) | ||||||
| 1358 | | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); | ||||||
| 1359 | for(var j = 0; j < 4; j++) | ||||||
| 1360 | { | ||||||
| 1361 | if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; | ||||||
| 1362 | else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); | ||||||
| 1363 | } | ||||||
| 1364 | } | ||||||
| 1365 | return str; | ||||||
| 1366 | } | ||||||
| 1367 | ENDTAG | ||||||
| 1368 | #################################################################### | ||||||
| 1369 | } | ||||||
| 1370 | #################################################################### | ||||||
| 1371 | } | ||||||
| 1372 | |||||||
| 1373 | 1; | ||||||
| 1374 | __END__ |