summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEudyptula <eitan@mosenkis.net>2009-06-25 15:22:42 -0400
committerEudyptula <eitan@mosenkis.net>2009-06-25 15:22:42 -0400
commita171039a434de5bb44af48c776bc7625a09c7752 (patch)
treebf9b39c864ee5a01a9f5d5b12173899aeab05897
parentCleaned up various unused bits of code; moved finished images to their own di... (diff)
downloadingenue-a171039a434de5bb44af48c776bc7625a09c7752.tar.gz
ingenue-a171039a434de5bb44af48c776bc7625a09c7752.tar.bz2
ingenue-a171039a434de5bb44af48c776bc7625a09c7752.zip
Added logout and user self-registration with email confirmation; Updates to sql_row_obj; PDO subclass for debugging
-rw-r--r--frontend/include/header.php12
-rw-r--r--frontend/pages/login.php24
-rw-r--r--frontend/pages/logout.php16
-rw-r--r--frontend/pages/register.php66
-rw-r--r--frontend/routing.csv4
-rw-r--r--shared/classes/0sql_row_obj.php89
-rw-r--r--shared/classes/build.php2
-rw-r--r--shared/classes/buildopt.php2
-rw-r--r--shared/classes/pdo.php8
-rw-r--r--shared/classes/registrationtoken.php41
-rw-r--r--shared/classes/session.php22
-rw-r--r--shared/classes/task.php2
-rw-r--r--shared/config.php3
-rw-r--r--shared/functions/xhtmlemail.php (renamed from frontend/functions/xhtmlemail.php)5
-rw-r--r--shared/include/dbinit.php2
15 files changed, 213 insertions, 85 deletions
diff --git a/frontend/include/header.php b/frontend/include/header.php
index 578605a..0822f68 100644
--- a/frontend/include/header.php
+++ b/frontend/include/header.php
@@ -37,7 +37,17 @@ echo '<li><a href="'.url('logs').'">Log viewer</a></li>';
</div>
<div id="top" class="box">
<?php
- echo (isset($S['user'])?'<a href="'.url('logout').'">Logout</a>':'<a href="'.url('login').'">Login</a>');
+ $links=array();
+ if (isset($S['user'])) {
+ $links['logout'.(strlen($S['request'])?'/'.$S['request']:'')]='Logout';
+ } else {
+ $links['login'.(strlen($S['request'])?'/'.$S['request']:'')]='Login';
+ $links['register']='Register';
+ }
+ foreach ($links as $url => $text) {
+ $links[$url]='<a href="'.url($url).'">'.htmlentities($text).'</a>';
+ }
+ echo implode(' &bull; ', $links);
?>
</div>
<div id="main" class="box">
diff --git a/frontend/pages/login.php b/frontend/pages/login.php
index 881a821..13eeb0a 100644
--- a/frontend/pages/login.php
+++ b/frontend/pages/login.php
@@ -2,28 +2,16 @@
function init_login() {
global $S, $request, $conf;
if (isset($S['user'])) {
+ // Should we let you continue to $request['go'] instead?
return 'welcome';
} else {
if (isset($request['email']) && isset($request['password'])) {
$r=$S['pdo']->query('SELECT * FROM `users` WHERE `email`='.$S['pdo']->quote($request['email']).' AND `passhash`="'.sha1($request['password']).'"');
if ($r->rowCount()) {
$S['user']=new sql_user($r->fetch(PDO::FETCH_ASSOC));
- $id=null;
- while (!$id) {
- $id=randstring(30);
- $r=$S['pdo']->query('SELECT * FROM `sessions` WHERE `id`="'.$id.'"');
- if ($r->rowCount()) {
- $id=null;
- }
- }
- $session=new sql_session($id, $S['user']->id, time(), $conf['sessionlength']);
- debug('setcookie', $conf['cookiename'].'='.$id);
- if (setcookie($conf['cookiename'], $session->id, time()+$conf['sessionlength'], $S['cookie_dir'], '', false, true)) {
- $session->write();
- $S['login_result']=true;
- }
+ $S['login.result']=sql_session::create();
} else {
- $S['login_result']=false;
+ $S['login.result']=false;
}
}
return array('title' => 'Login');
@@ -35,10 +23,10 @@ function body_login() {
$request['go']=$S['request'];
echo print_warning('Please sign in to access this page.');
}
- if (isset($S['login_result'])) {
- if ($S['login_result'] === 'error') {
+ if (isset($S['login.result'])) {
+ if ($S['login.result'] === 'error') {
echo print_error('An error occurred while signing you in.');
- } elseif ($S['login_result']) {
+ } elseif ($S['login.result']) {
echo print_success('Welcome, '.$S['user']->name);
echo '<a href="'.url(isset($request['go'])?$request['go']:'').'">Continue</a>';
die;
diff --git a/frontend/pages/logout.php b/frontend/pages/logout.php
new file mode 100644
index 0000000..6eccd3d
--- /dev/null
+++ b/frontend/pages/logout.php
@@ -0,0 +1,16 @@
+<?php
+function init_logout() {
+ global $S, $conf, $request;
+ if (isset($S['session'])) {
+ $S['session']->delete();
+ }
+ setcookie($conf['cookiename'], '', 1, $S['cookie_dir'], '', false, true);
+ if (isset($request['go'])) {
+ header('Location: '.url($request['go']));
+ }
+}
+function body_logout() {
+ echo print_success('Logged out.');
+ echo '<a href="'.url('login').'">Log back in</a>';
+}
+?>
diff --git a/frontend/pages/register.php b/frontend/pages/register.php
new file mode 100644
index 0000000..344ee25
--- /dev/null
+++ b/frontend/pages/register.php
@@ -0,0 +1,66 @@
+<?php
+function init_register() {
+ global $S;
+ if (isset($S['user'])) {
+ header('Location: '.url());
+ return 'welcome';
+ }
+ if (isset($request['token']) && preg_match('/^[a-zA-Z0-9]{30}$/', $request['token'])) {
+ $r=$S['pdo']->query('SELECT * FROM `tokens` WHERE `id`=\''.$request['token'].'\'');
+ if ($r->rowCount()) {
+ $S['register.token']=new sql_registrationtoken($r->fetch(PDO::FETCH_ASSOC));
+ if (isset($request['password'])) {
+ $S['register.fail']='';
+ if (!isset($request['name']) || !Validate::username($request['name']))
+ $S['register.fail'].=print_warning('The username you entered is invalid. Names must be at least two characters long and may contain alphanumeric characters, period, space, underscore, and dash.');
+ if (!isset($request['password']) || strlen($request['password']) <= 4)
+ $S['register.fail'].=print_warning('Please enter a password at least five characters long.');
+ if ($S['register.fail']=='') {
+ $S['user']=new sql_user(null, $S['register.token']->email, $request['name'], sha1($request['password']), '');
+ $S['user']->write();
+ $S['register.token']->delete();
+ unset($S['register.token']);
+ sql_session::create();
+ }
+ }
+ }
+ }
+ return array('title' => 'Register');
+}
+function body_register() {
+ global $S, $request, $conf;
+ if (isset($S['user']))
+ echo print_success('Account creation complete.');
+ elseif (isset($request['email'])) {
+ if (!Validate::email($request['email']))
+ echo print_warning('The email address you entered is invalid.').'<a href="javascript:history.go(-1)">Back</a>';
+ // 5.3.0 - goto print form
+ else {
+ if ($S['pdo']->query('SELECT COUNT(*) FROM `users` WHERE `email`='.$S['pdo']->quote($request['email']))->fetch(PDO::FETCH_COLUMN))
+ echo print_warning('An account already exists with this email address.').'<a href="'.url('login').'">Login</a>';
+ else {
+ if ($token=$S['pdo']->query('SELECT * FROM `registrationtokens` WHERE `email`='.$S['pdo']->quote($request['email']))->fetch(PDO::FETCH_ASSOC)) {
+ echo print_warning('A confirmation email has already been sent to this email address... sending another email.');
+ $token=new sql_registrationtoken($token);
+ } else {
+ $token=sql_registrationtoken::create();
+ $token->email=$request['email'];
+ }
+ $token->expire=time()+24*3600; // 24 Hours before expiration (not implemented)
+ $token->write();
+ xhtmlemail($request['email'], null, $conf['title'].' account creation', 'To complete your account registration, click this link: <a href="'.url('register/'.$token->id).'">'.url('register/'.$token->id).'</a>.');
+ echo print_success('You will receive an email soon at '.htmlentities($request['email']).' with instructions to finish creating your account.');
+ }
+ }
+ } elseif (isset($S['register.token'])) {
+ if (isset($S['register.fail']))
+ echo $S['register.fail'];
+ else
+ echo '<h3>Register</h3><form action="'.url('register').'" method="post"><input type="hidden" name="token" value="'.$request['token'].'" />Display name: <input name="name" /><br/>Password: <input type="password" name="password" /><br/><input type="submit" value="Create Account" /></form>';
+ } else
+ echo '<h3>Register</h3><form action="'.url('register').'" method="post">
+ E-mail: <input name="email" /><br/>
+ <input type="submit" value="Create Account" />
+ </form>';
+}
+?>
diff --git a/frontend/routing.csv b/frontend/routing.csv
index 841529d..4baf180 100644
--- a/frontend/routing.csv
+++ b/frontend/routing.csv
@@ -25,7 +25,11 @@
^download/([a-zA-Z0-9]{6})$ downloadimage build
# Session
^login$ login
+^login/(.+)$ login go
^logout$ logout
+^logout/(.+)$ logout go
+# Account stuff
+^register$ register
# Pass through
^(js)/([0-9a-zA-Z-_]+\.(js))$ passthrough dir file ext
^(images)/([0-9a-zA-Z-_]+\.(gif|jpg|jpeg|ico))$ passthrough dir file ext
diff --git a/shared/classes/0sql_row_obj.php b/shared/classes/0sql_row_obj.php
index f2f815f..5c55a62 100644
--- a/shared/classes/0sql_row_obj.php
+++ b/shared/classes/0sql_row_obj.php
@@ -47,7 +47,7 @@ abstract class sql_row_obj { // If the name of this class changes, it must be up
// Makes an SQL query using $sql and returns the resulting object
private static function sql_query($q) {
self::check_pdo_obj();
- // echo $q."\n";
+ debug('sql_row_obj::query', $q);
return self::$pdo->query($q);
}
public static function sql_quote_string($s) {
@@ -535,60 +535,34 @@ class sql_col {
public function __construct($array=null) {
if (is_array($array)) {
// TODO this should probably be a switch inside a foreach
- if (isset($array['type'])) {
+ if (isset($array['type']))
$this->type=strtoupper($array['type']); // To allow for lower-case types
- }
- if (isset($array['length'])) {
+ if (isset($array['length']))
$this->length=$array['length'];
- } elseif (isset($array['len'])) {
- $this->length=$array['len'];
- }
- if (isset($array['unsigned'])) {
+ if (isset($array['unsigned']))
$this->unsigned=$array['unsigned']?true:false; // To allow for non-booleans that can evaluate to boolean
- } elseif (isset($array['signed'])) {
- $this->unsigned=$array['signed']?false:true;
- }
- if (isset($array['charset'])) {
+ if (isset($array['charset']))
$this->charset=$array['charset'];
- }
- if (isset($array['collate'])) {
+ if (isset($array['collate']))
$this->collate=$array['collate'];
- }
- if (isset($array['not null'])) {
- $this->not_null=$array['not null']?true:false;
- } elseif (isset($array['not_null'])) {
+ if (isset($array['not_null']))
$this->not_null=$array['not_null']?true:false;
- } elseif (isset($array['null'])) {
- $this->not_null=$array['null']?false:true;
- }
- if ($this->is_numeric()) {
- if (isset($array['auto_increment'])) {
- $this->auto_increment=$array['auto_increment']?true:false;
- } elseif (isset($array['auto increment'])) {
- $this->auto_increment=$array['auto increment']?true:false;
- } elseif (isset($array['ai'])) {
- $this->auto_increment=$array['ai']?true:false;
- }
- }
- if (isset($array['default'])) {
+ if ($this->is_numeric() && isset($array['auto_increment']))
+ $this->auto_increment=$array['auto_increment']?true:false;
+ if (isset($array['default']))
$this->default=$array['default'];
- } elseif ($this->not_null) { // TODO add the default non-null val for the rest of types (http://dev.mysql.com/doc/refman/5.1/en/data-type-defaults.html)
- if ($this->is_numeric() && !$this->auto_increment) {
+ elseif ($this->not_null) { // TODO add the default non-null val for the rest of types (http://dev.mysql.com/doc/refman/5.1/en/data-type-defaults.html)
+ if ($this->is_numeric() && !$this->auto_increment)
$this->default=0;
- } elseif ($this->type == 'ENUM') {
+ elseif ($this->type == 'ENUM') {
// $this->default=$this->length; // TODO finish this
- } elseif ($this->is_string()) {
+ } elseif ($this->is_string())
$this->default='';
- }
}
- if (isset($array['unique'])) {
+ if (isset($array['unique']))
$this->unique=$array['unique']?true:false;
- }
- if (isset($array['refers to'])) {
- $this->refers_to=$array['refers to'];
- } elseif (isset($array['refersto'])) {
- $this->refers_to=$array['refersto'];
- }
+ if (isset($array['refers_to']))
+ $this->refers_to=$array['refers_to'];
} elseif (is_string($array)) {
$line=$array;
list($type, $line)=explode(' ', $line, 2);
@@ -654,7 +628,11 @@ class sql_col {
$this->default=$string;
break;
case 'COMMENT':
- $this->comment=$string;
+ if (preg_match('/^refers to: ([a-zA-Z0-9_$]+\.[a-zA-Z0-9_$]+)$/', $string, $match)) {
+ $this->refers_to=$match[1];
+ } else {
+ $this->comment=$string;
+ }
break;
}
break;
@@ -752,30 +730,25 @@ class sql_col {
// Returns the row used to create this column in the CREATE statement
public function describe() {
$d=$this->type.($this->has_length()?'('.$this->get_length().')':'');
- if ($this->is_numeric() && $this->unsigned) {
+ if ($this->is_numeric() && $this->unsigned)
$d.=' UNSIGNED';
- }
if ($this->is_string()) {
$d.=' CHARSET '.$this->charset;
- if (isset($this->collate)) {
+ if (isset($this->collate))
$d.=' COLLATE '.$this->collate;
- }
}
- if ($this->not_null) {
+ if ($this->not_null)
$d.=' NOT NULL';
- }
- if (isset($this->default)) {
+ if (isset($this->default))
$d.=' DEFAULT '.$this->sql_value($this->default);
- }
- if ($this->is_numeric() && $this->auto_increment) {
+ if ($this->is_numeric() && $this->auto_increment)
$d.=' AUTO_INCREMENT';
- }
- if ($this->unique === true) {
+ if ($this->unique === true)
$d.=' UNIQUE';
- }
- if (isset($this->comment)) {
+ if (isset($this->comment))
$d.=' COMMENT '.sql_row_obj::sql_quote_string($this->comment);
- }
+ elseif (isset($this->refers_to))
+ $d.=' COMMENT '.sql_row_obj::sql_quote_string('refers to: '.$this->refers_to);
return $d;
}
// Returns the array necessary to generate this column using the constructor
diff --git a/shared/classes/build.php b/shared/classes/build.php
index 54631ee..369425e 100644
--- a/shared/classes/build.php
+++ b/shared/classes/build.php
@@ -13,7 +13,7 @@ class sql_build extends sql_row_obj {
'unsigned' => true,
'not_null' => true,
'default' => 0,
- 'refers to' => 'users.id'
+ 'refers_to' => 'users.id'
),
'name' => array (
'type' => 'VARCHAR',
diff --git a/shared/classes/buildopt.php b/shared/classes/buildopt.php
index 92d24fd..b4b5226 100644
--- a/shared/classes/buildopt.php
+++ b/shared/classes/buildopt.php
@@ -6,7 +6,7 @@ class sql_buildopt extends sql_row_obj {
'length' => 6,
'not_null' => true,
'default' => '',
- 'refers to' => 'builds.id'
+ 'refers_to' => 'builds.id'
),
'name' => array (
'type' => 'VARCHAR',
diff --git a/shared/classes/pdo.php b/shared/classes/pdo.php
new file mode 100644
index 0000000..daf71ba
--- /dev/null
+++ b/shared/classes/pdo.php
@@ -0,0 +1,8 @@
+<?php
+class pdo_debug extends PDO {
+ function query($q, $a1=null, $a2=null, $a3=null) {
+ debug('pdo::query', $q);
+ return parent::query($q, $a1, $a2, $a3);
+ }
+}
+?>
diff --git a/shared/classes/registrationtoken.php b/shared/classes/registrationtoken.php
new file mode 100644
index 0000000..86e8d44
--- /dev/null
+++ b/shared/classes/registrationtoken.php
@@ -0,0 +1,41 @@
+<?php
+class sql_registrationtoken extends sql_row_obj {
+ protected $table='registrationtokens', $primary_key=array('id'), $columns=array(
+ 'id' => array (
+ 'type' => 'CHAR',
+ 'length' => 30,
+ 'not_null' => true,
+ 'default' => ''
+ ),
+ 'owner' => array (
+ 'type' => 'INT',
+ 'length' => 10,
+ 'unsigned' => true
+ ),
+ 'email' => array (
+ 'type' => 'VARCHAR',
+ 'length' => 255,
+ 'not_null' => true,
+ 'unique' => true
+ ),
+ 'expire' => array (
+ 'type' => 'INT',
+ 'length' => 10,
+ 'unsigned' => true,
+ 'not_null' => true,
+ 'default' => 0
+ )
+
+ );
+ static function create() {
+ global $S;
+ $id=null;
+ do {
+ $id=randstring(30);
+ if ($S['pdo']->query('SELECT COUNT(*) FROM `registrationtokens` WHERE `id`=\''.$id.'\'')->fetch(PDO::FETCH_COLUMN))
+ $id=null;
+ } while ($id==null);
+ return new sql_registrationtoken($id, null, null, null);
+ }
+}
+?>
diff --git a/shared/classes/session.php b/shared/classes/session.php
index 19575fe..e422b21 100644
--- a/shared/classes/session.php
+++ b/shared/classes/session.php
@@ -13,7 +13,7 @@ class sql_session extends sql_row_obj {
'unsigned' => true,
'not_null' => true,
'default' => 0,
- 'refers to' => 'users.id'
+ 'refers_to' => 'users.id'
),
'atime' => array (
'type' => 'INT',
@@ -31,5 +31,25 @@ class sql_session extends sql_row_obj {
)
);
+ // Creates a new session for the user at $S['user'] with a unique id, sends a cookie to the user and returns true for success, false for failure
+ static function create() {
+ global $S, $conf;
+ $id=null;
+ while (!$id) {
+ $id=randstring(30);
+ $r=$S['pdo']->query('SELECT * FROM `sessions` WHERE `id`="'.$id.'"');
+ if ($r->rowCount()) {
+ $id=null;
+ }
+ }
+ $S['session']=new sql_session($id, $S['user']->id, time(), $conf['sessionlength']);
+ debug('setcookie', $conf['cookiename'].'='.$id);
+ if (setcookie($conf['cookiename'], $S['session']->id, time()+$conf['sessionlength'], $S['cookie_dir'], '', false, true)) {
+ $S['session']->write();
+ return true;
+ } else {
+ return false;
+ }
+ }
}
?>
diff --git a/shared/classes/task.php b/shared/classes/task.php
index 30adb73..73bde43 100644
--- a/shared/classes/task.php
+++ b/shared/classes/task.php
@@ -13,7 +13,7 @@ class sql_task extends sql_row_obj {
'length' => 6,
'not_null' => true,
'default' => '',
- 'refers to' => 'builds.id'
+ 'refers_to' => 'builds.id'
),
'command' => array (
'type' => 'TEXT',
diff --git a/shared/config.php b/shared/config.php
index a8719ed..fb61824 100644
--- a/shared/config.php
+++ b/shared/config.php
@@ -10,9 +10,10 @@ $conf['cookiename']='ingenueid'; // Name of the cookie to send for keeping sessi
$conf['sessionlength']=1814400; // Time in seconds before sessions are purged
$conf['timezone']=10800; // Time difference in seconds between UTC and the default timezone
$conf['mod_rewrite']=true; // Use mod_rewrite for pretty URLs
+$conf['emailfrom']='noreply@gentoo.org'; // Used as the From: field in emails
$conf['check_email_dns']=true; // Use DNS to check the domain of submitted emails for validity
$conf['pkgdir_root']='/home/eitan/soc/tinderbox'; // The directory to recursively search for pkgdirs in
$conf['emerge_default_opts']='-t -v -K --color=y --root-deps=rdeps'; // DON'T CHANGE UNLESS YOU KNOW WHAT YOU'RE DOING
$conf['portdir']='/usr/portage'; // The directory conatining the portage tree to use (/usr/portage unless you have a reason to think otherwise)
-$conf['logview_max']=1000;
+$conf['logview_max']=1000; // The maximum number of log entries shown on one page (1000 is a good start)
?>
diff --git a/frontend/functions/xhtmlemail.php b/shared/functions/xhtmlemail.php
index 753a6dc..f07c99a 100644
--- a/frontend/functions/xhtmlemail.php
+++ b/shared/functions/xhtmlemail.php
@@ -8,11 +8,12 @@ function xhtmlemail($to,$from,$subj,$cont,$inheads=null) {
$heads='MIME-Version: 1.0' . "\r\n";
$heads.='Content-type: text/html; charset=utf-8' . "\r\n";
$heads.='From: '.$from."\r\n";
- $heads.='X-Mailer: MosBlog/'.MOSBLOG_VERSION."\r\n";
+ $heads.='X-Mailer: PHP/'.$conf['title']."\r\n";
if ($inheads!==null) {
- $heads.="\r\n".$inheads;
+ $heads.=$inheads."\r\n";
}
$cont='<?xml version="1.0" encoding="utf-8"?>'."\n".'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'."\n".'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'.$cont.'</html>'."\n";
+ $heads.='Content-length: '.strlen($cont)."\r\n";
return mail($to,$subj,$cont,$heads);
}
?>
diff --git a/shared/include/dbinit.php b/shared/include/dbinit.php
index 852b35f..49b5864 100644
--- a/shared/include/dbinit.php
+++ b/shared/include/dbinit.php
@@ -1,5 +1,5 @@
<?php
require_once(dirname(__FILE__).'/../config.php'); // Use __DIR__ in 5.3.0
-$S['pdo']=new PDO('mysql:dbname='.$conf['sqldb'].';host='.$conf['sqlhost'], $conf['sqluser'], $conf['sqlpass']);
+$S['pdo']=new pdo_debug('mysql:dbname='.$conf['sqldb'].';host='.$conf['sqlhost'], $conf['sqluser'], $conf['sqlpass']);
sql_row_obj::set_pdo_obj($S['pdo']);
?>