#7 two-phase email registration...

Unstable_(example)
open
nobody
5
2001-08-24
2001-08-24
No

Local.inc :

class TwoPhase_Challenge_Crypt_Auth extends Auth {
var $classname
= "TwoPhase_Challenge_Crypt_Auth";

var $lifetime = 15;

var $magic = "ADFGTKL4Q"; ## Challenge seed
var $database_class = "DB_CLASS";
var $database_table = "auth_user_md5";

function auth_preauth() {
global $username, $password, $challenge, $response;
return $this->auth_validatelogin();
}

function auth_loginform() {
global $sess;
global $challenge;
global $_PHPLIB;
global $HTTP_HOST;
global $TP_remember;
global $TP_login;

$challenge = md5(uniqid($this->magic));
$sess->register("challenge");

include($_PHPLIB
["libdir"] . "twophase_loginform.ihtml");
}

function generate_password($nb_char)
{
srand ((double) microtime() * 1000000);
$autorized_char = "9&FV/DAn[1Yp_UCw4#Tl=iL+Bz0W}
XKg3(EvrS-Jo5R2IM*xkH]Qu8~dqN6mtPaj7Z{hsyOf)Gcbe";
$pass = "";
while(strlen($pass)<$nb_char)
{
$pass .= substr($autorized_char,(rand()%(strlen
($autorized_char))),1);
}
return($pass);
}

function auth_validatelogin() {
global $username, $password, $challenge,
$response, $remember;

$this->auth["uname"]=stripslashes
($username); ## This provides access
for "loginform.ihtml"

$this->db->query(sprintf("select
user_id,perms,password ".
"from %s where username = '%s'",
$this->database_table,
addslashes(stripslashes
($username))));

while($this->db->next_record()) {
$uid = $this->db->f("user_id");
$perm = $this->db->f("perms");
$pass = $this->db->f("password"); ## Password
is stored as a md5 hash
}
$exspected_response = md5(stripslashes
($username).":$pass:$challenge");

switch($remember)
{
case "yes":
setcookie("twophase_remember", "yes", time()
+315360000);
setcookie("twophase_login", trim($username),
time()+315360000);
break;
case "no":
setcookie("twophase_remember", "no", time()
+315360000);
setcookie("twophase_login");
break;
}

if ($response == "") { ##
True when JS is disabled
if (md5($password) != $pass) { ##
md5 hash for non-JavaScript browsers
return false;
}
} elseif ($exspected_response != $response) { ##
Response is set, JS is enabled
return false;
}

## If perm is referenced then reset password to
force unique usage
if (strstr($perm, "referenced")) {
$fake_password = md5($this->generate_password
(10));
$this->db->query(sprintf("update %s set password
= '%s' where user_id = '%s'",
$this->database_table,
$fake_password,
$uid));
}
$this->auth["perm"] = $perm;
return $uid;

}
}

class TwoPhase_Default_Challenge_Crypt_Auth extends
TwoPhase_Challenge_Crypt_Auth {
var $classname
= "TwoPhase_Default_Challenge_Crypt_Auth";

var $nobody = true;
}

class TwoPhase_Perm extends Perm {
var $classname = "TwoPhase_Perm";

var $permissions = array(
"referenced" => 1,
"user" => 2,
"admin" => 4
);

function perm_invalid($does_have, $must_have) {
global $perm, $auth, $sess;
global $_PHPLIB;

include($_PHPLIB
["libdir"] . "twophase_perminvalid.ihtml");
}
}

twophase_loginform.ihtml :

<script language="JavaScript">
<!--
function check_email(emailStr)
{
var supported = 0;
if (window.RegExp)
{
var tempStr = "a";
var tempReg = new RegExp(tempStr);
if (tempReg.test(tempStr)) supported =
1;
}
if (!supported)
{
var newstr = "";
var at = false;
var dot = false;

if (emailStr.indexOf("@") != -1) {
at = true;
} else if (emailStr.indexOf(".") != -1) {
dot = true;
}
for (var i = 0; i < emailStr.length; i++) {
ch = emailStr.substring(i, i +
1)
if ((ch >= "A" && ch <= "Z")
|| (ch >= "a" && ch <= "z")
|| (ch == "@")
|| (ch == ".") || (ch == "_")
|| (ch == "-")
|| (ch >= "0" && ch <= "9")) {
newstr += ch;
if (ch == "@")
{

at=true;
}
if (ch == ".")
{

dot=true;
}
}
}
if ((at == true) && (dot == true)) {
return true;
}
else {
alert ("<? echo $msg_59 ?>");
return false;
}
}
else
{
var emailPat=new RegExp("^(.+)@(.+)$");
var specialChars="\\(\\)
<>@,;:\\\\\\\"\\.\\[\\]";
var validChars="\[^\\s" + specialChars
+ "\]";
var quotedUser="(\"[^\"]*\")";
var ipDomainPat=new RegExp("^([0-9]
{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$");
var atom=validChars + '+';
var word="(" + atom + "|" + quotedUser
+ ")";
var userPat=new RegExp("^" + word
+ "(\\." + word + ")*$");
var domainPat=new RegExp("^" + atom
+ "(\\." + atom +")*$");

var matchArray=emailStr.match
(emailPat);
if (matchArray==null)
{
alert("<? echo $msg_59 ?>");
return false;
}

var user=matchArray[1];
var domain=matchArray[2];
if (user.match(userPat)==null)
{
alert("<? echo $msg_59 ?>");
return false;
}

var IPArray=domain.match(ipDomainPat);
if (IPArray!=null)
{
for (var i=1;i<=4;i++)
{
if (IPArray[i]>255)
{
alert("<? echo
$msg_59 ?>");
return false;
}
}
return true;
}

var domainArray=domain.match
(domainPat);
if (domainArray==null)
{
alert("<? echo $msg_59 ?>");
return false;
}

var atomPat=new RegExp(atom,"g");
var domArr=domain.match(atomPat);
var len=domArr.length;
if (domArr[domArr.length-1].length<2
|| domArr[domArr.length-1].length>3)
{
alert("<? echo $msg_59 ?>");
return false;
}

if (len<2)
{
var errStr="<? echo $msg_59 ?
>";
alert(errStr);
return false;
}
return true;
}
}

var flag = true;
function field_clear(my_obj)
{
if(flag)
my_obj.value = '';
flag = false;
}

function check_form(my_obj)
{
if(my_obj.password.value.length > 5)
{
if(check_email(my_obj.username.value))
{
doChallengeResponse();
return true;
}
else
return false;
}
else
{
alert("<? echo $msg_44?>");
return false;
}
}
//-->
</script>
<p>
<? if ( isset
($username) ): ?>
<!-- failed login
code -->
Either :<br>
<ul>

<li>You have not yet registered : then <a
href="user_insert.php">Try it</a>

<li>or your email or password are invalid

<li><a href="password_forget.php?email=<? echo
urlencode($this->auth["uname"]) ?>">or you have lost
your password</a></font>";

</ul>
</font>
</td>
</tr>
</table>
<? endif ?>

<form name="login"
action="<?php print $this->url() ?>" method="post"
onSubmit="return check_form(this);">
<tr>
<td colspan=2>
<table
border="0" cellspacing="0" cellpadding="2">
<tr>

<td valign="top">

<table border="0" cellspacing="0"
cellpadding="2">

<tr>

<td>Email : </b></font></td>

<? if($twophase_remember
== "yes") {

if(trim($this->auth
["uname"]) != "") { ?>

<td><input
type="text" name="username" size="25" maxlength=255
value="<? echo $this->auth["uname"] ?>"></td>

<? } else { ?>

<td><input
type="text" name="username" size="25" maxlength=255
value="<? echo $twophase_login ?>"></td>

<? } ?>

<? } else { ?>

<td><input type="text"
name="username" size="25" maxlength=255 value="<?
print ((trim($this->auth["uname"]) != "") ? $this->auth
["uname"] : "your email") ?>" onfocus="field_clear
(this);"></td>

<? } ?>

<td></td>

</tr>

<tr>

<td>Password : </b></font></td>

<td><input type="password"
name="password" size="25" value="" maxlength=32></td>

<td></td>

</tr>

<tr>

<td colspan="2">

<? if
($twophase_remember == "yes") { ?>

Remember my
email : <input type="radio" name="remember"
value="yes" checked>yes   <input
type="radio" name="remember" value="no">no

<? } else { ?>

<? echo
Remember my email : <input type="radio"
name="remember"
value="yes">yes   <input type="radio"
name="remember" value="non" checked>no

<? } ?>

</td>

<td><input type="submit"
value=" OK "></td>

</tr>

</table>

<p>

<p>Do you have
forgotten your password ? <a
href="password_forgotten.php">Click here</a>

</td>

</tr>

</table>

</td>
</tr>

</table>
<p>
</td>
</tr>
<input type="hidden"
name="challenge" value="<?php print $challenge ?>">
<input type="hidden"
name="response" value="">
</form>
</table>
page_close();
?>

and in

twophase_perminvalid() :

<?
header("Location: password_update.php");
?>

Then in all the scripts that need "true" authenticated
user just put : $perm->check("user"); just after the
page_open()...

I've cut'n paste only the "interesting" part of my
scripts, so, if you have trouble to use it send me
email...

Discussion