Autoblocker privacy protection

This commit is contained in:
Tim Starling 2003-09-07 13:56:25 +00:00
parent dee8864299
commit ff0f56bc8c
12 changed files with 173 additions and 81 deletions

View file

@ -37,6 +37,11 @@ $wgDBsqlpassword = "sqlpass";
$wgDBminWordLen = 3; # Match this to your MySQL fulltext
$wgDBtransactions = false; # Set to true if using InnoDB tables
# Change this key to different sequence of 8 bytes, so that sysops cannot
# obtain the IP addresses of logged-in users.
$wgIPBlockKey = implode( "", array_map( "chr",
array( 57, 100, 182, 241, 93, 122, 40, 195 ) ) );
# Turn this on during database maintenance
# $wgReadOnly = true;

View file

@ -9,5 +9,5 @@
# update.php script.
#
$wgSoftwareRevision = 1001;
$wgSoftwareRevision = 1002;
?>

View file

@ -165,16 +165,23 @@ oldimage (Old versions of images stored for potential revert)
ipblocks (IP addresses and users blocked from editing)
ipb_id
Primary key, introduced for privacy.
ipb_address
Blocked IP address in dotted-quad form or ""
Blocked IP address in dotted-quad form or user name.
ipb_user
Blocked user ID or 0.
Blocked user ID or 0 for IP blocks.
ipb_by
User ID who made the block.
ipb_reason
Text comment made by blocker.
ipb_timestamp
Creation (or refresh) date in standard YMDHMS form. IP
blocks expire automatically.
ipb_auto
Indicates that the IP address was banned because a banned
user accessed a page through it. If this is 1, ipb_address
will be hidden.
random (Random page queue)

View file

@ -1,52 +1,51 @@
<?
# Blocks and bans object
#
#TODO: This could be used everywhere, but it isn't.
#
# All the functions in this class assume the object is either explicitly
# loaded or filled. It is not load-on-demand.
# loaded or filled. It is not load-on-demand. There are no accessors.
#
# To use delete(), you only need to fill $mAddress
class Block
{
var $mAddress, $mUser, $mBy, $mReason, $mTimestamp;
var $mAddress, $mUser, $mBy, $mReason, $mTimestamp, $mAuto, $mId;
function Block( $address = "", $user = "", $by = 0, $reason = "", $timestamp = "" )
function Block( $address = "", $user = "", $by = 0, $reason = "",
$timestamp = "" , $auto = 0)
{
$this->mAddress = $address;
$this->mUser = $user;
$this->mBy = $by;
$this->mReason = $reason;
$this->mTimestamp = $timestamp;
$this->mAuto = $auto;
}
/*static*/ function newFromDB( $address, $user = 0, $killExpired = true )
{
/*static*/ function newFromDB( $address, $user = 0, $killExpired = true ) {
$ban = new Block();
$ban->load( $address, $user, $killExpired );
return $ban;
}
function clear()
{
function clear() {
$mAddress = $mReason = $mTimestamp = "";
$mUser = $mBy = 0;
}
# Get a ban from the DB, with either the given address or the given username
function load( $address, $user = 0, $killExpired = true )
{
function load( $address, $user = 0, $killExpired = true ) {
$fname = "Block::load";
$ret = false;
$killed = false;
if ( 0 == $user ) {
$sql = "SELECT * FROM ipblocks WHERE ipb_address='$address'";
$sql = "SELECT * FROM ipblocks WHERE ipb_address='" . wfStrencode( $address ) . "'";
} else {
$sql = "SELECT * FROM ipblocks WHERE (ipb_address='$address' OR ipb_user={$user})";
$sql = "SELECT * FROM ipblocks WHERE (ipb_address='" . wfStrencode( $address ) .
"' OR ipb_user={$user})";
}
$res = wfQuery( $sql, $fname );
if ( 0 == wfNumRows( $res ) ) {
@ -58,15 +57,19 @@ class Block
$this->initFromRow( $row );
if ( $killExpired ) {
# If requested, delete expired rows
do {
$killed = $this->deleteIfExpired();
$row = wfFetchObject( $res );
if ( $killed ) {
$row = wfFetchObject( $res );
if ( $row ) {
$this->initFromRow( $row );
}
}
} while ( $killed && $row );
# If there were any left after the killing finished, return true
if ( $row == false ) {
if ( !$row ) {
$ret = false;
$this->clear();
} else {
@ -80,18 +83,18 @@ class Block
return $ret;
}
function initFromRow( $row )
{
function initFromRow( $row ) {
$this->mAddress = $row->ipb_address;
$this->mReason = $row->ipb_reason;
$this->mTimestamp = $row->ipb_timestamp;
$this->mUser = $row->ipb_user;
$this->mBy = $row->ipb_by;
$this->mAuto = $row->ipb_auto;
$this->mId = $row->ipb_id;
}
# Callback with a Block object for every block
/*static*/ function enumBlocks( $callback, $tag, $killExpired = true )
{
/*static*/ function enumBlocks( $callback, $tag, $killExpired = true ) {
$sql = "SELECT * FROM ipblocks ORDER BY ipb_timestamp";
$res = wfQuery( $sql, "Block::enumBans" );
$block = new Block();
@ -109,22 +112,26 @@ class Block
wfFreeResult( $res );
}
function delete()
{
wfQuery( "DELETE FROM ipblocks WHERE ipb_address='{$this->mAddress}'",
"Block::delete" );
function delete() {
$fname = "Block::delete";
if ( $this->mAddress == "" ) {
$sql = "DELETE FROM ipblocks WHERE ipb_id={$this->mId}";
} else {
$sql = "DELETE FROM ipblocks WHERE ipb_address='" .
wfStrencode( $this->mAddress ) . "'";
}
wfQuery( $sql, "Block::delete" );
}
function insert()
{
$sql = "INSERT INTO ipblocks (ipb_address, ipb_user, ipb_by, " .
"ipb_reason, ipb_timestamp ) VALUES ('{$this->mAddress}', {$this->mUser}, " .
"{$this->mBy}, '" . wfStrencode( $this->mReason ) . "','{$this->mTimestamp}')";
function insert() {
$sql = "INSERT INTO ipblocks
(ipb_address, ipb_user, ipb_by, ipb_reason, ipb_timestamp, ipb_auto )
VALUES ('" . wfStrencode( $this->mAddress ) . "', {$this->mUser}, {$this->mBy}, '" .
wfStrencode( $this->mReason ) . "','{$this->mTimestamp}', {$this->mAuto})";
wfQuery( $sql, "Block::insert" );
}
function deleteIfExpired()
{
function deleteIfExpired() {
if ( $this->isExpired() ) {
$this->delete();
return true;
@ -133,8 +140,7 @@ class Block
}
}
function isExpired()
{
function isExpired() {
global $wgIPBlockExpiration, $wgUserBlockExpiration;
$period = $this->mUser ? $wgUserBlockExpiration : $wgIPBlockExpiration;
@ -152,17 +158,14 @@ class Block
}
}
function isValid()
{
function isValid() {
return $this->mAddress != "";
}
function updateTimestamp()
{
$sql = "UPDATE ipblocks SET ipb_timestamp='" . wfTimestampNow() . "' WHERE ipb_address='{$this->mAddress}'";
function updateTimestamp() {
wfQuery( "UPDATE ipblocks SET ipb_timestamp='" . wfTimestampNow() .
"' WHERE ipb_address='{$this->mAddress}'", "Block::updateTimestamp" );
"' WHERE ipb_address='" . wfStrencode( $this->mAddress ) . "'", "Block::updateTimestamp" );
}
}
?>

View file

@ -23,7 +23,6 @@ $wgEmergencyContact = "wikiadmin@" . getenv( "SERVER_NAME" );
#$wgPasswordSender = "Wikipedia Mail <apache@www.wikipedia.org>";
$wgPasswordSender = "Wikipedia Mail <apache@www.wikipedia.org>\r\nReply-To: webmaster@www.wikipedia.org";
# MySQL settings
#
$wgDBserver = "localhost";

View file

@ -59,14 +59,13 @@ class IPBlockForm {
function doSubmit()
{
global $wgOut, $wgUser, $wgLang;
global $ip, $wpBlockAddress, $wpBlockReason, $wgSysopUserBlocks;
$fname = "IPBlockForm::doSubmit";
global $ip, $wpBlockAddress, $wpBlockReason, $wgSysopUserBans;
$userId = 0;
if ( ! preg_match( "/\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/",
$wpBlockAddress ) )
{
if ( $wgSysopUserBlocks ) {
if ( $wgSysopUserBans ) {
$userId = User::idFromName( $wpBlockAddress );
if ( $userId == 0 ) {
$this->showForm( wfMsg( "badipaddress" ) );
@ -83,12 +82,9 @@ class IPBlockForm {
}
# Note: for a user block, ipb_address is only for display purposes
$sql = "INSERT INTO ipblocks (ipb_address, ipb_user, ipb_by, " .
"ipb_reason, ipb_timestamp ) VALUES ('{$wpBlockAddress}', {$userId}, " .
$wgUser->getID() . ", '" . wfStrencode( $wpBlockReason ) . "','" .
wfTimestampNow() . "')";
wfQuery( $sql, $fname );
$ban = new Block( $wpBlockAddress, $userId, $wgUser->getID(),
wfStrencode( $wpBlockReason ), wfTimestampNow(), 0 );
$ban->insert();
$success = wfLocalUrl( $wgLang->specialPage( "Blockip" ),
"action=success&ip={$wpBlockAddress}" );

View file

@ -57,18 +57,24 @@ class IPUnblockForm {
</form>\n" );
}
function doSubmit()
{
global $wgOut, $wgUser, $wgLang;
global $ip, $wpUnblockAddress;
$fname = "IPUnblockForm::doSubmit";
global $wpUnblockAddress;
$sql = "DELETE FROM ipblocks WHERE ipb_address='{$wpUnblockAddress}'";
wfQuery( $sql, $fname );
$block = new Block();
if ( $wpUnblockAddress{0} == "#" ) {
$block->mId = substr( $wpUnblockAddress, 1 );
} else {
$block->mAddress = $wpUnblockAddress;
}
$block->delete();
$success = wfLocalUrl( $wgLang->specialPage( "Ipblocklist" ),
"action=success&ip={$wpUnblockAddress}" );
"action=success&ip=" . urlencode($wpUnblockAddress) );
$wgOut->redirect( $success );
}
@ -86,29 +92,35 @@ class IPUnblockForm {
}
}
# Callback function
# Callback function to output a block
function wfAddRow( $block, $tag ) {
global $wgOut, $wgUser, $wgLang, $ip;
$sk = $wgUser->getSkin();
$addr = $block->mAddress;
# Hide addresses blocked by User::spreadBlocks, for privacy
$addr = $block->mAuto ? "#{$block->mId}" : $block->mAddress;
$name = User::whoIs( $block->mBy );
$ulink = $sk->makeKnownLink( $wgLang->getNsText( Namespace::getUser() ). ":{$name}", $name );
$d = $wgLang->timeanddate( $block->mTimestamp, true );
$line = str_replace( "$1", $d, wfMsg( "blocklistline" ) );
$line = str_replace( "$2", $ulink, $line );
$line = str_replace( "$3", $block->mAddress, $line );
$line = str_replace( "$3", $addr, $line );
$wgOut->addHTML( "<li>{$line}" );
$clink = "<a href=\"" . wfLocalUrlE( $wgLang->specialPage(
"Contributions" ), "target={$addr}" ) . "\">" .
wfMsg( "contribslink" ) . "</a>";
$wgOut->addHTML( " ({$clink})" );
if ( !$block->mAuto ) {
$clink = "<a href=\"" . wfLocalUrlE( $wgLang->specialPage(
"Contributions" ), "target={$block->mAddress}" ) . "\">" .
wfMsg( "contribslink" ) . "</a>";
$wgOut->addHTML( " ({$clink})" );
}
if ( $wgUser->isSysop() ) {
$ublink = "<a href=\"" . wfLocalUrlE( $wgLang->specialPage(
"Ipblocklist" ), "action=unblock&ip={$addr}" ) . "\">" .
"Ipblocklist" ), "action=unblock&ip=" . urlencode( $addr ) ) . "\">" .
wfMsg( "unblocklink" ) . "</a>";
$wgOut->addHTML( " ({$ublink})" );
}

View file

@ -94,14 +94,15 @@ class User {
{
if ( -1 != $this->mBlockedby ) { return; }
$ban = new Ban();
if ( $ban->load( getenv( "REMOTE_ADDR" ), $this->mId ) ) {
$block = new Block();
if ( !$block->load( getenv( "REMOTE_ADDR" ), $this->mId ) ) {
wfDebug( getenv( "REMOTE_ADDR" ) ." is not blocked\n" );
$this->mBlockedby = 0;
return;
}
$this->mBlockedby = $ban->by;
$this->mBlockreason = $ban->reason;
$this->mBlockedby = $block->mBy;
$this->mBlockreason = $block->mReason;
}
function isBlocked()
@ -588,7 +589,7 @@ class User {
return;
}
# Make a new ban object with the desired properties
# Make a new block object with the desired properties
wfDebug( "Autoblocking {$this->mUserName}@{$addr}\n" );
$ipblock->mAddress = $addr;
$ipblock->mUser = 0;
@ -596,6 +597,7 @@ class User {
$ipblock->mReason = str_replace( "$1", $this->getName(), wfMsg( "autoblocker" ) );
$ipblock->mReason = str_replace( "$2", $userblock->mReason, $ipblock->mReason );
$ipblock->mTimestamp = wfTimestampNow();
$ipblock->mAuto = 1;
# Insert it
$ipblock->insert();

View file

@ -170,7 +170,8 @@ function copydirectory( $source, $dest ) {
$handle = opendir( $source );
while ( false !== ( $f = readdir( $handle ) ) ) {
if ( "." == $f{0} ) continue;
if ( "CVS" == $f ) continue;
# Something made all my "CVSs" go lowercase :(
if ( !strcasecmp( "CVS", $f ) ) continue;
copyfile( $source, $f, $dest );
}
}

View file

@ -5,6 +5,9 @@
-- Only UNIQUE keys are defined here; the rest are added by
-- indexes.sql.
--
-- If you change the main development branch version of this
-- file, please add an appropriate ALTER TABLE to update.php,
-- and increment the version number in Version.php.
DROP TABLE IF EXISTS user;
CREATE TABLE user (
@ -104,11 +107,14 @@ CREATE TABLE site_stats (
DROP TABLE IF EXISTS ipblocks;
CREATE TABLE ipblocks (
ipb_id int(8) NOT NULL auto_increment,
ipb_address varchar(40) binary NOT NULL default '',
ipb_user int(8) unsigned NOT NULL default '0',
ipb_by int(8) unsigned NOT NULL default '0',
ipb_reason tinyblob NOT NULL default '',
ipb_timestamp char(14) binary NOT NULL default ''
ipb_timestamp char(14) binary NOT NULL default '',
ipb_auto tinyint(1) NOT NULL default '0',
UNIQUE KEY ipb_id
) TYPE=MyISAM PACK_KEYS=1;
DROP TABLE IF EXISTS image;

View file

@ -27,6 +27,7 @@ include_once( "Version.php" );
include_once( "{$IP}/Setup.php" );
$wgTitle = Title::newFromText( "Update script" );
$wgCommandLineMode = true;
$wgAlterSpecs = array();
do_revision_updates();
@ -89,7 +90,8 @@ function copydirectory( $source, $dest ) {
$handle = opendir( $source );
while ( false !== ( $f = readdir( $handle ) ) ) {
if ( "." == $f{0} ) continue;
if ( "CVS" == $f ) continue;
# Windows turned all my CVS->cvs :(
if ( !strcasecmp ( "CVS", $f ) ) continue;
copyfile( $source, $f, $dest );
}
}
@ -102,13 +104,32 @@ function readconsole() {
}
function do_revision_updates() {
global $wgSoftwareRevision;
global $wgSoftwareRevision, $wgAlterSpecs, $wgDBserver, $wgDBadminuser;
global $wgDBadminpassword, $wgDBname;
if ( $wgSoftwareRevision < 1001 ) { update_passwords(); }
if ( $wgSoftwareRevision < 1002 ) { alter_ipblocks(); }
# Run ALTER TABLE queries.
if ( count( $wgAlterSpecs ) ) {
$rconn = mysql_connect( $wgDBserver, $wgDBadminuser, $wgDBadminpassword );
mysql_select_db( $wgDBname );
print "\n";
foreach ( $wgAlterSpecs as $table => $specs ) {
$sql = "ALTER TABLE $table $specs";
print "$sql;\n";
$res = mysql_query( $sql, $rconn );
if ( $res === false ) {
print "MySQL error: " . mysql_error( $rconn ) . "\n";
}
}
mysql_close( $rconn );
}
}
function update_passwords() {
$fname = "Update scripte: update_passwords()";
$fname = "Update script: update_passwords()";
print "\nIt appears that you need to update the user passwords in your\n" .
"database. If you have already done this (if you've run this update\n" .
"script once before, for example), doing so again will make all your\n" .
@ -132,4 +153,36 @@ function update_passwords() {
}
}
function alter_ipblocks() {
global $wgAlterSpecs;
$fname = "Update script: alter_ipblocks";
if ( field_exists( "ipblocks", "ipb_id" ) ) {
return;
}
if ( array_key_exists( "ipblocks", $wgAlterSpecs ) ) {
$wgAlterSpecs["ipblocks"] .= ",";
}
$wgAlterSpecs["ipblocks"] .=
"ADD ipb_auto tinyint(1) NOT NULL default '0', ".
"ADD ipb_id int(8) NOT NULL auto_increment,".
"ADD PRIMARY KEY (ipb_id)";
}
function field_exists( $table, $field ) {
$fname = "Update script: field_exists";
$res = wfQuery( "DESCRIBE $table", $fname );
$found = false;
while ( $row = wfFetchObject( $res ) ) {
if ( $row->Field == $field ) {
$found = true;
break;
}
}
return $found;
}
?>

View file

@ -16,6 +16,14 @@ include_once( "$IP/Setup.php" );
wfProfileIn( "main-misc-setup" );
OutputPage::setEncodings(); # Not really used yet
# Useful debug output
wfDebug( "\nStart request\n" );
wfDebug( "$REQUEST_METHOD $REQUEST_URI\n" );
$headers = getallheaders();
foreach ($headers as $name => $value) {
wfDebug( "$name: $value\n" );
}
# Query string fields
#
global $action, $title, $search, $go, $target, $printable;