Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4060432
TemporaryAccountLogger.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
TemporaryAccountLogger.php
View Options
<?php
namespace
MediaWiki\CheckUser\Logging
;
use
MediaWiki\Logging\DatabaseLogEntry
;
use
MediaWiki\Logging\ManualLogEntry
;
use
MediaWiki\Title\TitleFactory
;
use
MediaWiki\User\ActorStore
;
use
MediaWiki\User\UserIdentity
;
use
Psr\Log\LoggerInterface
;
use
Wikimedia\Assert\Assert
;
use
Wikimedia\Assert\ParameterAssertionException
;
use
Wikimedia\IPUtils
;
use
Wikimedia\Rdbms\DBError
;
use
Wikimedia\Rdbms\IConnectionProvider
;
/**
* Defines the API for the component responsible for logging the following interactions:
*
* - A user views IP addresses for a temporary account
* - A user views temporary accounts on a given IP address or range
* - A user enables temporary account IP viewing
* - A user disables temporary account IP viewing
*
* All the above interactions will be logged to the `logging` table with a log type
* `checkuser-temporary-account`.
*/
class
TemporaryAccountLogger
{
/**
* Represents a user (the performer) viewing IP addresses for a temporary account.
*
* @var string
*/
public
const
ACTION_VIEW_IPS
=
'view-ips'
;
/** @var string Represents a user viewing the temporary accounts on a specific IP address */
public
const
ACTION_VIEW_TEMPORARY_ACCOUNTS_ON_IP
=
'view-temporary-accounts-on-ip'
;
/** @var string Represents a user globally viewing the temporary accounts on a specific IP address */
public
const
ACTION_VIEW_TEMPORARY_ACCOUNTS_ON_IP_GLOBAL
=
'view-temp-accounts-on-ip-global'
;
/**
* Represents a user enabling or disabling their own access to view IPs
*
* @var string
*/
public
const
ACTION_CHANGE_ACCESS
=
'change-access'
;
public
const
ACTION_ACCESS_ENABLED
=
'enable'
;
public
const
ACTION_ACCESS_DISABLED
=
'disable'
;
public
const
ACTION_GLOBAL_ACCESS_ENABLED
=
'enable-globally'
;
public
const
ACTION_GLOBAL_ACCESS_DISABLED
=
'disable-globally'
;
/**
* Represents a user enabling or disabling IP auto-reveal mode
*
* @var string
*/
public
const
ACTION_CHANGE_AUTO_REVEAL
=
'change-auto-reveal'
;
public
const
ACTION_AUTO_REVEAL_ENABLED
=
'enable-auto-reveal'
;
public
const
ACTION_AUTO_REVEAL_DISABLED
=
'disable-auto-reveal'
;
/**
* @var string
*/
public
const
LOG_TYPE
=
'checkuser-temporary-account'
;
private
ActorStore
$actorStore
;
private
LoggerInterface
$logger
;
private
IConnectionProvider
$dbProvider
;
private
TitleFactory
$titleFactory
;
private
int
$delay
;
/**
* @param ActorStore $actorStore
* @param LoggerInterface $logger
* @param IConnectionProvider $dbProvider
* @param TitleFactory $titleFactory
* @param int $delay The number of seconds after which a duplicate log entry can be
* created for a debounced log
* @throws ParameterAssertionException
*/
public
function
__construct
(
ActorStore
$actorStore
,
LoggerInterface
$logger
,
IConnectionProvider
$dbProvider
,
TitleFactory
$titleFactory
,
int
$delay
)
{
Assert
::
parameter
(
$delay
>
0
,
'delay'
,
'delay must be positive'
);
$this
->
actorStore
=
$actorStore
;
$this
->
logger
=
$logger
;
$this
->
dbProvider
=
$dbProvider
;
$this
->
titleFactory
=
$titleFactory
;
$this
->
delay
=
$delay
;
}
/**
* Logs the user (the performer) viewing temporary accounts on a given IP address or range.
* This action can be performed locally or globally.
*
* @param UserIdentity $performer
* @param string $ip IP address or range
* @param int $timestamp
*/
public
function
logViewTemporaryAccountsOnIP
(
UserIdentity
$performer
,
string
$ip
,
int
$timestamp
,
bool
$global
=
false
):
void
{
$action
=
$global
?
self
::
ACTION_VIEW_TEMPORARY_ACCOUNTS_ON_IP_GLOBAL
:
self
::
ACTION_VIEW_TEMPORARY_ACCOUNTS_ON_IP
;
$this
->
debouncedLog
(
$performer
,
IPUtils
::
prettifyIP
(
$ip
),
$action
,
$timestamp
);
}
/**
* Logs the user (the performer) viewing IP addresses for a temporary account.
*
* @param UserIdentity $performer
* @param string $tempUser
* @param int $timestamp
*/
public
function
logViewIPs
(
UserIdentity
$performer
,
string
$tempUser
,
int
$timestamp
):
void
{
$this
->
debouncedLog
(
$performer
,
$tempUser
,
self
::
ACTION_VIEW_IPS
,
$timestamp
);
}
/**
* Logs the user (the performer) viewing IP addresses for a temporary account, while
* auto-reveal mode is enabled. These actions are logged temporarily rather than permanently,
* to avoid flooding the on-wiki logs.
*
* @param string $username The name of the performer who viewed the IPs
* @param string $tempUser
*/
public
function
logViewIPsWithAutoReveal
(
string
$username
,
string
$tempUser
):
void
{
$this
->
logger
->
info
(
'{username} viewed IP addresses for {target}'
,
[
'username'
=>
$username
,
'target'
=>
$tempUser
,
]
);
}
/**
* Log when the user enables their own access locally.
*
* @param UserIdentity $performer
*/
public
function
logAccessEnabled
(
UserIdentity
$performer
):
void
{
$this
->
logAccessChanged
(
$performer
,
self
::
ACTION_ACCESS_ENABLED
);
}
/**
* Log when the user disables their own access locally.
*
* @param UserIdentity $performer
*/
public
function
logAccessDisabled
(
UserIdentity
$performer
):
void
{
$this
->
logAccessChanged
(
$performer
,
self
::
ACTION_ACCESS_DISABLED
);
}
/**
* Log when the user enables their own access globally.
*
* @param UserIdentity $performer
*/
public
function
logGlobalAccessEnabled
(
UserIdentity
$performer
):
void
{
$this
->
logAccessChanged
(
$performer
,
self
::
ACTION_GLOBAL_ACCESS_ENABLED
);
}
/**
* Log when the user disables their own access globally.
*
* @param UserIdentity $performer
*/
public
function
logGlobalAccessDisabled
(
UserIdentity
$performer
):
void
{
$this
->
logAccessChanged
(
$performer
,
self
::
ACTION_GLOBAL_ACCESS_DISABLED
);
}
/**
* @param UserIdentity $performer
* @param string $action One of the following action constants from this class:
* - ACTION_ACCESS_ENABLED
* - ACTION_ACCESS_DISABLED
* - ACTION_GLOBAL_ACCESS_ENABLED
* - ACTION_GLOBAL_ACCESS_DISABLED
*/
private
function
logAccessChanged
(
UserIdentity
$performer
,
string
$action
)
{
$params
=
[
'4::changeType'
=>
$action
];
$this
->
log
(
$performer
,
$performer
->
getName
(),
self
::
ACTION_CHANGE_ACCESS
,
$params
);
}
/**
* Log when the user enables IP auto-reveal.
*
* @param UserIdentity $performer
* @param int $expiry
*/
public
function
logAutoRevealAccessEnabled
(
UserIdentity
$performer
,
int
$expiry
):
void
{
$params
=
[
'4::changeType'
=>
self
::
ACTION_AUTO_REVEAL_ENABLED
,
'5::expiry'
=>
$expiry
,
];
$this
->
logAutoRevealChanged
(
$performer
,
$params
);
}
/**
* Log when the user disables IP auto-reveal.
*
* @param UserIdentity $performer
*/
public
function
logAutoRevealAccessDisabled
(
UserIdentity
$performer
):
void
{
$params
=
[
'4::changeType'
=>
self
::
ACTION_AUTO_REVEAL_DISABLED
];
$this
->
logAutoRevealChanged
(
$performer
,
$params
);
}
/**
* @param UserIdentity $performer
* @param array $params
*/
private
function
logAutoRevealChanged
(
UserIdentity
$performer
,
array
$params
)
{
$this
->
log
(
$performer
,
$performer
->
getName
(),
self
::
ACTION_CHANGE_AUTO_REVEAL
,
$params
);
}
/**
* @param UserIdentity $performer
* @param string $target
* @param string $action
* @param int $timestamp
* @param array|null $params
*/
private
function
debouncedLog
(
UserIdentity
$performer
,
string
$target
,
string
$action
,
int
$timestamp
,
?
array
$params
=
[]
):
void
{
$dbw
=
$this
->
dbProvider
->
getPrimaryDatabase
();
$timestampMinusDelay
=
$timestamp
-
$this
->
delay
;
$actorId
=
$this
->
actorStore
->
findActorId
(
$performer
,
$dbw
);
if
(
!
$actorId
)
{
$this
->
log
(
$performer
,
$target
,
$action
,
$params
,
$timestamp
);
return
;
}
$targetAsTitle
=
$this
->
titleFactory
->
makeTitle
(
NS_USER
,
$target
);
$logRows
=
DatabaseLogEntry
::
newSelectQueryBuilder
(
$dbw
)
->
where
(
[
'log_type'
=>
self
::
LOG_TYPE
,
'log_action'
=>
$action
,
'log_actor'
=>
$actorId
,
'log_namespace'
=>
$targetAsTitle
->
getNamespace
(),
'log_title'
=>
$targetAsTitle
->
getDBkey
(),
$dbw
->
expr
(
'log_timestamp'
,
'>'
,
$dbw
->
timestamp
(
$timestampMinusDelay
)
),
]
)
->
caller
(
__METHOD__
)
->
fetchResultSet
();
$shouldLog
=
true
;
foreach
(
$logRows
as
$logRow
)
{
$logEntry
=
DatabaseLogEntry
::
newFromRow
(
$logRow
);
$logParams
=
$logEntry
->
getParameters
();
if
(
$logParams
==
$params
)
{
$shouldLog
=
false
;
break
;
}
}
if
(
$shouldLog
)
{
$this
->
log
(
$performer
,
$target
,
$action
,
$params
,
$timestamp
);
}
}
/**
* @param UserIdentity $performer
* @param string $target
* @param string $action
* @param array $params
* @param int|null $timestamp
*/
private
function
log
(
UserIdentity
$performer
,
string
$target
,
string
$action
,
array
$params
,
?
int
$timestamp
=
null
):
void
{
$logEntry
=
$this
->
createManualLogEntry
(
$action
);
$logEntry
->
setPerformer
(
$performer
);
$logEntry
->
setTarget
(
$this
->
titleFactory
->
makeTitle
(
NS_USER
,
$target
)
);
$logEntry
->
setParameters
(
$params
);
if
(
$timestamp
)
{
$logEntry
->
setTimestamp
(
wfTimestamp
(
TS_MW
,
$timestamp
)
);
}
try
{
$logEntry
->
insert
(
$this
->
dbProvider
->
getPrimaryDatabase
()
);
}
catch
(
DBError
)
{
$this
->
logger
->
critical
(
'CheckUser temporary account log entry was not recorded. '
.
'This means checks can occur without being auditable. '
.
'Immediate fix required.'
);
}
}
/**
* Allow other extensions to write relevant logs to the temporary accounts log
*
* Sources:
* - AbuseFilter
* + af-view-protected-var-value
*/
public
function
logFromExternal
(
UserIdentity
$performer
,
string
$target
,
string
$action
,
array
$params
=
[],
bool
$debounce
=
false
,
?
int
$timestamp
=
null
)
{
if
(
!
$timestamp
)
{
$timestamp
=
(
int
)
wfTimestamp
();
}
if
(
$debounce
)
{
$this
->
debouncedLog
(
$performer
,
$target
,
$action
,
$timestamp
,
$params
);
}
else
{
$this
->
log
(
$performer
,
$target
,
$action
,
$params
,
$timestamp
);
}
}
/**
* There is no `LogEntryFactory` (or `Logger::insert()` method) in MediaWiki Core to inject
* via the constructor so use this method to isolate the creation of `LogEntry` objects during
* testing.
*
* @private
*
* @param string $subtype
* @return ManualLogEntry
*/
protected
function
createManualLogEntry
(
string
$subtype
):
ManualLogEntry
{
return
new
ManualLogEntry
(
self
::
LOG_TYPE
,
$subtype
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Aug 16 2026, 07:28 (12 w, 2 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
b4/e9/1dfa9aca706a81cba325f52f8e97
Default Alt Text
TemporaryAccountLogger.php (10 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment