* Int Serialized record version.
* @ingroup Constants
*/
-define( 'MW_USER_VERSION', 8 );
+define( 'MW_USER_VERSION', 9 );
/**
* String Some punctuation to prevent editing from broken text-mangling proxies.
'mEmailAuthenticated',
'mEmailToken',
'mEmailTokenExpires',
+ 'mPasswordExpires',
'mRegistration',
'mEditCount',
// user_groups table
$mEmail, $mTouched, $mToken, $mEmailAuthenticated,
$mEmailToken, $mEmailTokenExpires, $mRegistration, $mEditCount,
$mGroups, $mOptionOverrides;
+
+ protected $mPasswordExpires;
//@}
/**
}
}
+ /**
+ * Expire a user's password
+ * @since 1.23
+ * @param $ts Mixed: optional timestamp to convert, default 0 for the current time
+ */
+ public function expirePassword( $ts = 0 ) {
+ $this->load();
+ $timestamp = wfTimestamp( TS_MW, $ts );
+ $this->mPasswordExpires = $timestamp;
+ $this->saveSettings();
+ }
+
+ /**
+ * Clear the password expiration for a user
+ * @since 1.23
+ * @param bool $load ensure user object is loaded first
+ */
+ public function resetPasswordExpiration( $load = true ) {
+ global $wgPasswordExpirationDays;
+ if ( $load ) {
+ $this->load();
+ }
+ $newExpire = null;
+ if ( $wgPasswordExpirationDays ) {
+ $newExpire = wfTimestamp(
+ TS_MW,
+ time() + ( $wgPasswordExpirationDays * 24 * 3600 )
+ );
+ }
+ // Give extensions a chance to force an expiration
+ wfRunHooks( 'ResetPasswordExpiration', array( $this, &$newExpire ) );
+ $this->mPasswordExpires = $newExpire;
+ }
+
+ /**
+ * Check if the user's password is expired.
+ * TODO: Put this and password length into a PasswordPolicy object
+ * @since 1.23
+ * @return string|bool The expiration type, or false if not expired
+ * hard: A password change is required to login
+ * soft: Allow login, but encourage password change
+ * false: Password is not expired
+ */
+ public function getPasswordExpired() {
+ global $wgPasswordExpireGrace;
+ $expired = false;
+ $now = wfTimestamp();
+ $expiration = $this->getPasswordExpireDate();
+ $expUnix = wfTimestamp( TS_UNIX, $expiration );
+ if ( $expiration !== null && $expUnix < $now ) {
+ $expired = ( $expUnix + $wgPasswordExpireGrace < $now ) ? 'hard' : 'soft';
+ }
+ return $expired;
+ }
+
+ /**
+ * Get this user's password expiration date. Since this may be using
+ * the cached User object, we assume that whatever mechanism is setting
+ * the expiration date is also expiring the User cache.
+ * @since 1.23
+ * @return string|false the datestamp of the expiration, or null if not set
+ */
+ public function getPasswordExpireDate() {
+ $this->load();
+ return $this->mPasswordExpires;
+ }
+
/**
* Does a string look like an e-mail address?
*
$this->mEmailAuthenticated = null;
$this->mEmailToken = '';
$this->mEmailTokenExpires = null;
+ $this->mPasswordExpires = null;
+ $this->resetPasswordExpiration( false );
$this->mRegistration = wfTimestamp( TS_MW );
$this->mGroups = array();
$this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
$this->mEmailToken = $row->user_email_token;
$this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
+ $this->mPasswordExpires = wfTimestampOrNull( TS_MW, $row->user_password_expires );
$this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration );
} else {
$all = false;
$ipList = gethostbynamel( $host );
if ( $ipList ) {
- wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $base!\n" );
+ wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $base!" );
$found = true;
break;
} else {
- wfDebugLog( 'dnsblacklist', "Requested $host, not found in $base.\n" );
+ wfDebugLog( 'dnsblacklist', "Requested $host, not found in $base." );
}
}
}
* - 'registered-checkmatrix' - as above, using the 'checkmatrix' type.
* - 'userjs' - preferences with names starting with 'userjs-', intended to
* be used by user scripts.
+ * - 'special' - "preferences" that are not accessible via User::getOptions
+ * or User::setOptions.
* - 'unused' - preferences about which MediaWiki doesn't know anything.
* These are usually legacy options, removed in newer versions.
*
'registered-multiselect',
'registered-checkmatrix',
'userjs',
+ 'special',
'unused'
);
}
$prefs = Preferences::getPreferences( $this, $context );
$mapping = array();
+ // Pull out the "special" options, so they don't get converted as
+ // multiselect or checkmatrix.
+ $specialOptions = array_fill_keys( Preferences::getSaveBlacklist(), true );
+ foreach ( $specialOptions as $name => $value ) {
+ unset( $prefs[$name] );
+ }
+
// Multiselect and checkmatrix options are stored in the database with
// one key per option, each having a boolean value. Extract those keys.
$multiselectOptions = array();
$mapping[$key] = 'registered-multiselect';
} elseif ( isset( $checkmatrixOptions[$key] ) ) {
$mapping[$key] = 'registered-checkmatrix';
+ } elseif ( isset( $specialOptions[$key] ) ) {
+ $mapping[$key] = 'special';
} elseif ( substr( $key, 0, 7 ) === 'userjs-' ) {
$mapping[$key] = 'userjs';
} else {
'user_token' => strval( $this->mToken ),
'user_email_token' => $this->mEmailToken,
'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
+ 'user_password_expires' => $dbw->timestampOrNull( $this->mPasswordExpires ),
), array( /* WHERE */
'user_id' => $this->mId
), __METHOD__
return;
}
- $defaultOptions = self::getDefaultOptions();
-
$userId = $this->getId();
$insert_rows = array();
- $changedOptions = array_diff_assoc( $saveOptions, $defaultOptions );
- foreach ( $changedOptions as $key => $value ) {
- if ( $value === false || is_null( $value ) ) {
- continue;
+ foreach ( $saveOptions as $key => $value ) {
+ // Don't bother storing default values
+ $defaultOption = self::getDefaultOption( $key );
+ if ( ( is_null( $defaultOption ) &&
+ !( $value === false || is_null( $value ) ) ) ||
+ $value != $defaultOption ) {
+ $insert_rows[] = array(
+ 'up_user' => $userId,
+ 'up_property' => $key,
+ 'up_value' => $value,
+ );
}
- $insert_rows[] = array(
- 'up_user' => $userId,
- 'up_property' => $key,
- 'up_value' => $value,
- );
}
$dbw = wfGetDB( DB_MASTER );
'user_email_authenticated',
'user_email_token',
'user_email_token_expires',
+ 'user_password_expires',
'user_registration',
'user_editcount',
);