--- a/includes/clientside/static/autocomplete.js Sat Nov 17 22:12:31 2007 -0500
+++ b/includes/clientside/static/autocomplete.js Sat Nov 17 22:25:37 2007 -0500
@@ -1,5 +1,6 @@
/*
* Auto-completing page/username fields
+ * NOTE: A more efficient version of the username field is used for Mozilla browsers. The updated code is in autofill.js.
*/
// The ultimate Javascript app: AJAX auto-completion, which responds to up/down arrow keys, the enter key, and the escape key
--- a/includes/clientside/static/autofill.js Sat Nov 17 22:12:31 2007 -0500
+++ b/includes/clientside/static/autofill.js Sat Nov 17 22:25:37 2007 -0500
@@ -1,5 +1,6 @@
/**
- * Javascript auto-completion for form fields.
+ * Javascript auto-completion for form fields. This supercedes the code in autocomplete.js for MOZILLA ONLY. It doesn't seem to work real
+ * well with other browsers yet.
*/
var af_current = false;
@@ -245,8 +246,12 @@
form._af_acting = false;
return true;
}
+ else
+ {
+ form._af_acting = true;
+ return true;
+ }
}
- form._af_acting = true;
}
}
@@ -255,8 +260,9 @@
var key = this.event.keyCode;
if ( key == this.KEY_ENTER && !this.repeat )
{
+ submitAuthorized = true;
var form = findParentForm($(this.field_id).object);
- form._af_acting = false;
+ form._af_acting = false;
return true;
}
switch(key)
@@ -420,6 +426,7 @@
setTimeout('var body = document.getElementsByTagName("body")[0]; var div = document.getElementById("'+div.id+'"); if ( div ) body.removeChild(div);', 20);
delete(this.boxes[i]);
}
+ this.boxes = new Array();
this.box_id = false;
this.state = false;
}
@@ -432,6 +439,7 @@
else if ( this.state )
ta.value = this.state;
this.destroy();
+ findParentForm($(this.field_id.object))._af_acting = false;
}
this.sleep = function()
--- a/includes/comment.php Sat Nov 17 22:12:31 2007 -0500
+++ b/includes/comment.php Sat Nov 17 22:25:37 2007 -0500
@@ -270,6 +270,7 @@
$real_code = $session->get_captcha($data['captcha_id']);
if ( $real_code != $data['captcha_code'] )
$errors[] = 'The confirmation code you entered was incorrect.';
+ $session->kill_captcha();
}
if ( count($errors) > 0 )
--- a/includes/pageutils.php Sat Nov 17 22:12:31 2007 -0500
+++ b/includes/pageutils.php Sat Nov 17 22:25:37 2007 -0500
@@ -344,9 +344,34 @@
$paths->page_exists = true;
}
- $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
- $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
- if(($prot || !$wiki) && $session->user_level < USER_LEVEL_ADMIN ) return('You are not authorized to edit this page.');
+ // Check page protection
+
+ $is_protected = false;
+ $page_data =& $paths->pages[$pname];
+ // Is the protection semi?
+ if ( $page_data['protected'] == 2 )
+ {
+ $is_protected = true;
+ // Page is semi-protected. Has the user been here for at least 4 days?
+ // 345600 seconds = 4 days
+ if ( $session->user_logged_in && ( $session->reg_time + 345600 ) <= time() )
+ $is_protected = false;
+ }
+ // Is the protection full?
+ else if ( $page_data['protected'] == 1 )
+ {
+ $is_protected = true;
+ }
+
+ // If it's protected and we DON'T have even_when_protected rights, bail out
+ if ( $is_protected && !$session->get_permissions('even_when_protected') )
+ {
+ return 'You don\'t have the necessary permissions to edit this page.';
+ }
+
+ // We're skipping the wiki mode check here because by default edit_page pemissions are AUTH_WIKIMODE.
+ // The exception here is the user's own userpage, which is overridden at the time of account creation.
+ // At that point it's set to AUTH_ALLOW, but obviously only for the user's own userpage.
// Strip potentially harmful tags and PHP from the message, dependent upon permissions settings
$message = RenderMan::preprocess_text($message, false, false);
--- a/includes/sessions.php Sat Nov 17 22:12:31 2007 -0500
+++ b/includes/sessions.php Sat Nov 17 22:25:37 2007 -0500
@@ -1060,7 +1060,7 @@
{
// Stash it in a cookie
// For now, make the cookie last forever, we can change this in 1.1.x
- setcookie( 'sid', $session_key, time()+315360000, scriptPath.'/', null, ( isset($_SERVER['HTTPS']) ) );
+ setcookie( 'sid', $session_key, time()+315360000, scriptPath.'/', null, ( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ) );
$_COOKIE['sid'] = $session_key;
}
// $keyhash is stored in the database, this is for compatibility with the older DB structure
@@ -2632,15 +2632,30 @@
function make_captcha($len = 7)
{
- $chars = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9');
- $s = '';
- for($i=0;$i<$len;$i++) $s .= $chars[mt_rand(0, count($chars)-1)];
+ $code = $this->generate_captcha_code($len);
$hash = md5(microtime() . mt_rand());
$this->sql('INSERT INTO '.table_prefix.'session_keys(session_key,salt,auth_level,source_ip,user_id) VALUES(\''.$hash.'\', \''.$s.'\', -1, \''.ip2hex($_SERVER['REMOTE_ADDR']).'\', -2);');
return $hash;
}
/**
+ * Generates the actual confirmation code text.
+ * @param int String length
+ * @return string
+ */
+
+ function generate_captcha_code($len = 7)
+ {
+ $chars = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9');
+ $s = '';
+ for ( $i = 0; $i < $len; $i++ )
+ {
+ $s .= $chars[mt_rand(0, count($chars)-1)];
+ }
+ return $s;
+ }
+
+ /**
* For the given code ID, returns the correct CAPTCHA code, or false on failure
* @param string $hash The unique ID assigned to the code
* @return string The correct confirmation code
@@ -2650,18 +2665,24 @@
{
global $db, $session, $paths, $template, $plugins; // Common objects
$s = $this->sql('SELECT salt FROM '.table_prefix.'session_keys WHERE session_key=\''.$db->escape($hash).'\' AND source_ip=\''.ip2hex($_SERVER['REMOTE_ADDR']).'\';');
- if($db->numrows() < 1) return false;
+ if ( $db->numrows() < 1 )
+ {
+ return false;
+ }
$r = $db->fetchrow();
+ $db->free_result();
+ $this->sql('DELETE FROM ' . table_prefix . 'session_keys WHERE salt=\'' . $db->escape($r['salt']) . '\';');
return $r['salt'];
}
/**
- * Deletes all CAPTCHA codes cached in the DB for this user.
+ * (AS OF 1.0.2: Deprecated. Captcha codes are now killed on first fetch for security.) Deletes all CAPTCHA codes cached in the DB for this user.
*/
function kill_captcha()
{
- $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE user_id=-2 AND source_ip=\''.ip2hex($_SERVER['REMOTE_ADDR']).'\';');
+ // $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE user_id=-2 AND source_ip=\''.ip2hex($_SERVER['REMOTE_ADDR']).'\';');
+ return true;
}
/**
--- a/index.php Sat Nov 17 22:12:31 2007 -0500
+++ b/index.php Sat Nov 17 22:25:37 2007 -0500
@@ -1,8 +1,8 @@
<?php
-/**
+/*
* Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0.2 (Coblynau)
+ * Version 1.1.1
* Copyright (C) 2006-2007 Dan Fuhry
*
* This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/install.php Sat Nov 17 22:12:31 2007 -0500
+++ b/install.php Sat Nov 17 22:25:37 2007 -0500
@@ -730,7 +730,7 @@
die('root'.$e);
}
$rsp = 'good';
- $q = mysql_query('USE '.$dbname, $conn);
+ $q = mysql_query('USE `' . mysql_real_escape_string($dbname) . '`;', $conn);
if(!$q)
{
$e = mysql_error();
@@ -763,7 +763,7 @@
else
die('auth'.$e);
}
- $q = mysql_query('USE '.$dbname, $conn);
+ $q = mysql_query('USE `' . mysql_real_escape_string($dbname) . '`;', $conn);
if(!$q)
{
$e = mysql_error();
--- a/plugins/SpecialUserFuncs.php Sat Nov 17 22:12:31 2007 -0500
+++ b/plugins/SpecialUserFuncs.php Sat Nov 17 22:25:37 2007 -0500
@@ -502,6 +502,7 @@
$_GET['coppa'] = ( isset($_POST['coppa']) ) ? $_POST['coppa'] : 'x';
$captcharesult = $session->get_captcha($_POST['captchahash']);
+ $session->kill_captcha();
if($captcharesult != $_POST['captchacode'])
{
$s = $lang->get('user_reg_err_captcha');
@@ -884,8 +885,10 @@
if(!namegood)
{
- var r = new RegExp('^([A-z0-9 \.:\!@\#\*]+){2,}$', 'g');
- if(frm.username.value.match(r))
+ <?php
+ // sorry for this ugly hack but jedit gets f***ed otherwise
+ echo 'if(frm.username.value.match(/^([A-z0-9 \.:\!@\#\*]+){2,}$/ig))';
+ ?>
{
document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/unknown.gif';
document.getElementById('e_username').innerHTML = ' ';
@@ -1152,19 +1155,44 @@
function page_Special_Captcha()
{
global $db, $session, $paths, $template, $plugins; // Common objects
- if($paths->getParam(0) == 'make')
+ if ( $paths->getParam(0) == 'make' )
{
$session->kill_captcha();
echo $session->make_captcha();
return;
}
+
$hash = $paths->getParam(0);
- if(!$hash || !preg_match('#^([0-9a-f]*){32,32}$#i', $hash)) $paths->main_page();
- $code = $session->get_captcha($hash);
- if(!$code) die('Invalid hash or IP address incorrect.');
- require(ENANO_ROOT.'/includes/captcha.php');
+ if ( !$hash || !preg_match('#^([0-9a-f]*){32,32}$#i', $hash) )
+ {
+ $paths->main_page();
+ }
+
+ // Determine code length
+ $ip = ip2hex($_SERVER['REMOTE_ADDR']);
+ if ( !$ip )
+ die('(very desperate) Hacking attempt');
+ $q = $db->sql_query('SELECT CHAR_LENGTH(salt) AS len FROM ' . table_prefix . 'session_keys WHERE session_key = \'' . $db->escape($hash) . '\' AND source_ip = \'' . $db->escape($ip) . '\';');
+ if ( !$q )
+ $db->_die('SpecialUserFuncs selecting CAPTCHA code');
+ if ( $db->numrows() < 1 )
+ die('Invalid hash or hacking attempt by IP');
+
+ // Generate code
+ $row = $db->fetchrow();
+ $db->free_result();
+ $len = intval($row['len']);
+ if ( $len < 4 )
+ $len = 7;
+ $code = $session->generate_captcha_code($len);
+
+ // Update database with new code
+ $q = $db->sql_query('UPDATE ' . table_prefix . 'session_keys SET salt = \'' . $code . '\' WHERE session_key = \'' . $db->escape($hash) . '\' AND source_ip = \'' . $db->escape($ip) . '\';');
+ if ( !$q )
+ $db->_die('SpecialUserFuncs generating new CAPTCHA confirmation code');
+
+ require ( ENANO_ROOT.'/includes/captcha.php' );
$captcha = new captcha($code);
- //header('Content-disposition: attachment; filename=autocaptcha.png');
$captcha->make_image();
exit;
}
--- a/schema.sql Sat Nov 17 22:12:31 2007 -0500
+++ b/schema.sql Sat Nov 17 22:25:37 2007 -0500
@@ -52,8 +52,9 @@
page_id varchar(63),
namespace varchar(16) NOT NULL default 'Article',
page_text text,
- char_tag varchar(63)
-) CHARACTER SET `utf8`;
+ char_tag varchar(63),
+ FULLTEXT KEY {{TABLE_PREFIX}}page_search_idx (page_id, namespace, page_text)
+) ENGINE = MYISAM CHARACTER SET `utf8`;
CREATE TABLE {{TABLE_PREFIX}}pages(
page_order int(8),
@@ -316,7 +317,7 @@
('powered_btn', '1');
INSERT INTO {{TABLE_PREFIX}}page_text(page_id, namespace, page_text, char_tag) VALUES
- ('Main_Page', 'Article', '=== Enano has been successfully installed! ===\n\nYou have finished installing Enano on this server. Congratulations!', '');
+ ('Main_Page', 'Article', '=== Enano has been successfully installed and is working. ===\n\nIf you can see this message, it means that you\'ve finished the Enano setup process and are ready to start building your website. Congratulations!\n\nTo edit this front page, click the Log In button to the left, enter the credentials you provided during the installation, and click the Edit This Page button that appears on the blue toolbar just above this text. You can also [http://docs.enanocms.org/Help:2.4 learn more] about editing pages.\n\nTo create more pages, use the Create a Page button to the left. If you enabled wiki mode, you don\'t have to log in first, however your IP address will be shown in the page history.\n\nVisit the [http://docs.enanocms.org/Help:Contents Enano documentation project website] to learn more about administering your site effectively and keeping things secure.\n\n\'\'\'NOTE:\'\'\' You\'ve just installed an unstable version of Enano. This release is completely unsupported and may contain security issues or serious usability bugs. You should not use this release on a production website. The Enano team will not provide any type of support at all for this experimental release.', '');
INSERT INTO {{TABLE_PREFIX}}pages(page_order, name, urlname, namespace, special, visible, comments_on, protected, delvotes, delvote_ips) VALUES
(NULL, 'Main Page', 'Main_Page', 'Article', 0, 1, 1, 1, 0, '');
--- a/upgrade.sql Sat Nov 17 22:12:31 2007 -0500
+++ b/upgrade.sql Sat Nov 17 22:25:37 2007 -0500
@@ -63,6 +63,8 @@
---BEGIN 1.0RC1---
-- Not too many DB changes in this release - that's a good sign ;-)
ALTER TABLE {{TABLE_PREFIX}}search_index MODIFY COLUMN word varbinary(64) NOT NULL;
+-- This is to correct an issue encountered upgrading a stock Win2k3 + IIS setup
+ALTER TABLE {{TABLE_PREFIX}}page_text ENGINE = MYISAM;
CREATE FULLTEXT INDEX {{TABLE_PREFIX}}page_search_idx ON {{TABLE_PREFIX}}page_text(page_id,namespace,page_text);
UPDATE {{TABLE_PREFIX}}users SET user_level=3 WHERE user_level=2;
UPDATE {{TABLE_PREFIX}}sidebar SET block_content='[[$NS_USER$$USERNAME$|User page]]\n[[$NS_SPECIAL$Contributions/$USERNAME$|My Contributions]]\n{if user_logged_in}\n[[$NS_SPECIAL$Preferences|Preferences]]\n[[$NS_SPECIAL$PrivateMessages|Private messages]]\n[[$NS_SPECIAL$Usergroups|Group control panel]]\n$THEME_LINK$\n{/if}\n{if user_logged_in}\n$LOGOUT_LINK$\n{else}\n[[$NS_SPECIAL$Register|Create an account]]\n$LOGIN_LINK$\n[[$NS_SPECIAL$Login/$NS_SPECIAL$PrivateMessages|Private messages]]\n{/if}',block_name='$USERNAME$' WHERE ( block_name='$USERNAME' OR block_name='$USERNAME$' ) AND item_id=3;