Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4150555
BlockManagerTest.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
31 KB
Referenced Files
None
Subscribers
None
BlockManagerTest.php
View Options
<?php
use
MediaWiki\Block\AbstractBlock
;
use
MediaWiki\Block\Block
;
use
MediaWiki\Block\BlockManager
;
use
MediaWiki\Block\CompositeBlock
;
use
MediaWiki\Block\DatabaseBlock
;
use
MediaWiki\Block\SystemBlock
;
use
MediaWiki\MainConfigNames
;
use
MediaWiki\Request\FauxRequest
;
use
MediaWiki\Request\FauxResponse
;
use
MediaWiki\User\User
;
use
MediaWiki\User\UserIdentityValue
;
use
Psr\Log\NullLogger
;
use
Wikimedia\TestingAccessWrapper
;
/**
* @group Blocking
* @group Database
* @covers \MediaWiki\Block\BlockManager
*/
class
BlockManagerTest
extends
MediaWikiIntegrationTestCase
{
use
TestAllServiceOptionsUsed
;
protected
User
$user
;
protected
User
$sysopUser
;
private
array
$blockManagerConfig
;
protected
function
setUp
():
void
{
parent
::
setUp
();
$this
->
user
=
$this
->
getTestUser
()->
getUser
();
$this
->
sysopUser
=
$this
->
getTestSysop
()->
getUser
();
$this
->
blockManagerConfig
=
[
MainConfigNames
::
ApplyIpBlocksToXff
=>
true
,
MainConfigNames
::
CookieSetOnAutoblock
=>
true
,
MainConfigNames
::
CookieSetOnIpBlock
=>
true
,
MainConfigNames
::
DnsBlacklistUrls
=>
[],
MainConfigNames
::
EnableDnsBlacklist
=>
true
,
MainConfigNames
::
ProxyList
=>
[],
MainConfigNames
::
ProxyWhitelist
=>
[],
MainConfigNames
::
SecretKey
=>
false
,
MainConfigNames
::
SoftBlockRanges
=>
[],
];
}
private
function
getBlockManager
(
$overrideConfig
)
{
return
new
BlockManager
(
...
$this
->
getBlockManagerConstructorArgs
(
$overrideConfig
)
);
}
private
function
getBlockManagerConstructorArgs
(
$overrideConfig
)
{
$blockManagerConfig
=
array_merge
(
$this
->
blockManagerConfig
,
$overrideConfig
);
$this
->
overrideConfigValues
(
$blockManagerConfig
);
$services
=
$this
->
getServiceContainer
();
return
[
new
LoggedServiceOptions
(
self
::
$serviceOptionsAccessLog
,
BlockManager
::
CONSTRUCTOR_OPTIONS
,
$services
->
getMainConfig
()
),
$services
->
getUserFactory
(),
$services
->
getUserIdentityUtils
(),
new
NullLogger
(),
$services
->
getHookContainer
(),
$services
->
getDatabaseBlockStore
(),
$services
->
getBlockTargetFactory
(),
$services
->
getProxyLookup
()
];
}
public
function
testGetBlock
()
{
// Reset so that hooks are called
$permissionManager
=
$this
->
getServiceContainer
()->
getPermissionManager
();
$permissionManager
->
invalidateUsersRightsCache
();
$onGetUserBlockCalled
=
false
;
$onGetUserBlockIP
=
false
;
$this
->
setTemporaryHook
(
'GetUserBlock'
,
static
function
(
$user
,
$ip
,
&
$block
)
use
(
&
$onGetUserBlockCalled
,
&
$onGetUserBlockIP
)
{
$onGetUserBlockCalled
=
true
;
$onGetUserBlockIP
=
$ip
;
return
true
;
}
);
$blockManager
=
$this
->
getBlockManager
(
[]
);
$block
=
$blockManager
->
getBlock
(
$this
->
user
,
null
,
false
);
// We don't actually care about the block, just whether or not the right hooks were called
$this
->
assertTrue
(
$onGetUserBlockCalled
,
'Check that HookRunner::onGetUserBlock was called'
);
$this
->
assertNull
(
$onGetUserBlockIP
,
'The `GetUserBlock` hook should have been called with null since we '
.
'didn
\'
t pass a request'
);
}
private
function
extractBlockOptions
(
$options
)
{
$blockOptions
=
$options
[
'blockOptions'
];
if
(
$options
[
'target'
]
)
{
$blockOptions
[
'address'
]
=
$options
[
'target'
];
}
else
{
$blockOptions
[
'targetUser'
]
=
$this
->
user
;
}
$blockOptions
[
'by'
]
??=
$this
->
sysopUser
;
return
$blockOptions
;
}
/**
* @dataProvider provideBlocksForShouldApplyCookieBlock
*/
public
function
testGetBlockFromCookieValue
(
$options
,
$expected
)
{
/** @var BlockManager $blockManager */
$blockManager
=
TestingAccessWrapper
::
newFromObject
(
$this
->
getBlockManager
(
[
MainConfigNames
::
CookieSetOnAutoblock
=>
true
,
MainConfigNames
::
CookieSetOnIpBlock
=>
true
,
]
)
);
$block
=
$this
->
getServiceContainer
()->
getDatabaseBlockStore
()
->
insertBlockWithParams
(
$this
->
extractBlockOptions
(
$options
)
);
$user
=
$options
[
'registered'
]
?
$this
->
user
:
new
User
();
$user
->
getRequest
()->
setCookie
(
'BlockID'
,
$blockManager
->
getCookieValue
(
$block
)
);
$this
->
assertSame
(
$expected
,
(
bool
)
$blockManager
->
getBlockFromCookieValue
(
$user
,
$user
->
getRequest
()
)
);
}
/**
* @dataProvider provideBlocksForShouldApplyCookieBlock
*/
public
function
testTrackBlockWithCookieRemovesBlocks
(
$options
,
$expectKeepCookie
)
{
/** @var BlockManager $blockManager */
$blockManager
=
TestingAccessWrapper
::
newFromObject
(
$this
->
getBlockManager
(
[
MainConfigNames
::
CookieSetOnAutoblock
=>
true
,
MainConfigNames
::
CookieSetOnIpBlock
=>
true
,
]
)
);
$block
=
$this
->
getServiceContainer
()->
getDatabaseBlockStore
()
->
insertBlockWithParams
(
$this
->
extractBlockOptions
(
$options
)
);
$user
=
$options
[
'registered'
]
?
$this
->
user
:
new
User
();
$user
->
getRequest
()->
setCookie
(
'BlockID'
,
$blockManager
->
getCookieValue
(
$block
)
);
$response
=
new
FauxResponse
;
$blockManager
->
trackBlockWithCookie
(
$user
,
$response
);
$this
->
assertCount
(
$expectKeepCookie
?
0
:
1
,
$response
->
getCookies
()
);
}
public
static
function
provideBlocksForShouldApplyCookieBlock
()
{
return
[
'Autoblocking user block'
=>
[
[
'target'
=>
''
,
'registered'
=>
true
,
'blockOptions'
=>
[
'enableAutoblock'
=>
true
],
],
true
,
],
'Autoblocking user block for anonymous user'
=>
[
[
'target'
=>
''
,
'registered'
=>
false
,
'blockOptions'
=>
[
'enableAutoblock'
=>
true
],
],
true
,
],
'Non-autoblocking user block'
=>
[
[
'target'
=>
''
,
'registered'
=>
true
,
'blockOptions'
=>
[],
],
false
,
],
'IP block for anonymous user'
=>
[
[
'target'
=>
'127.0.0.1'
,
'registered'
=>
false
,
'blockOptions'
=>
[],
],
true
,
],
'IP block for logged in user'
=>
[
[
'target'
=>
'127.0.0.1'
,
'registered'
=>
true
,
'blockOptions'
=>
[],
],
false
,
],
'IP range block for anonymous user'
=>
[
[
'target'
=>
'127.0.0.0/8'
,
'registered'
=>
false
,
'blockOptions'
=>
[],
],
true
,
],
];
}
/**
* @dataProvider provideIsLocallyBlockedProxy
*/
public
function
testIsLocallyBlockedProxy
(
$proxyList
,
$expected
)
{
/** @var BlockManager $blockManager */
$blockManager
=
TestingAccessWrapper
::
newFromObject
(
$this
->
getBlockManager
(
[
MainConfigNames
::
ProxyList
=>
$proxyList
]
)
);
$ip
=
'1.2.3.4'
;
$this
->
assertSame
(
$expected
,
$blockManager
->
isLocallyBlockedProxy
(
$ip
)
);
}
public
static
function
provideIsLocallyBlockedProxy
()
{
return
[
'Proxy list is empty'
=>
[
[],
false
],
'Proxy list contains IP'
=>
[
[
'1.2.3.4'
],
true
],
'Proxy list contains IP as value'
=>
[
[
'test'
=>
'1.2.3.4'
],
true
],
'Proxy list contains range that covers IP'
=>
[
[
'1.2.3.0/16'
],
true
],
];
}
/**
* @dataProvider provideIsDnsBlacklisted
*/
public
function
testIsDnsBlacklisted
(
$options
,
$expected
)
{
$blockManagerConfig
=
[
MainConfigNames
::
EnableDnsBlacklist
=>
true
,
MainConfigNames
::
DnsBlacklistUrls
=>
$options
[
'blacklist'
],
MainConfigNames
::
ProxyWhitelist
=>
$options
[
'whitelist'
],
];
$blockManager
=
$this
->
getMockBuilder
(
BlockManager
::
class
)
->
setConstructorArgs
(
$this
->
getBlockManagerConstructorArgs
(
$blockManagerConfig
)
)
->
onlyMethods
(
[
'checkHost'
]
)
->
getMock
();
$blockManager
->
method
(
'checkHost'
)
->
willReturnMap
(
[
[
$options
[
'dnsblQuery'
],
$options
[
'dnsblResponse'
],
]
]
);
$this
->
assertSame
(
$expected
,
$blockManager
->
isDnsBlacklisted
(
$options
[
'ip'
],
$options
[
'checkWhitelist'
]
)
);
}
public
static
function
provideIsDnsBlacklisted
()
{
$dnsblFound
=
[
'127.0.0.2'
];
$dnsblNotFound
=
false
;
return
[
'IP is blacklisted'
=>
[
[
'blacklist'
=>
[
'dnsbl.test'
],
'ip'
=>
'127.0.0.1'
,
'dnsblQuery'
=>
'1.0.0.127.dnsbl.test'
,
'dnsblResponse'
=>
$dnsblFound
,
'whitelist'
=>
[],
'checkWhitelist'
=>
false
,
],
true
,
],
'IP is blacklisted; blacklist has key'
=>
[
[
'blacklist'
=>
[
[
'dnsbl.test'
,
'key'
]
],
'ip'
=>
'127.0.0.1'
,
'dnsblQuery'
=>
'key.1.0.0.127.dnsbl.test'
,
'dnsblResponse'
=>
$dnsblFound
,
'whitelist'
=>
[],
'checkWhitelist'
=>
false
,
],
true
,
],
'IP is blacklisted; blacklist is array'
=>
[
[
'blacklist'
=>
[
[
'dnsbl.test'
]
],
'ip'
=>
'127.0.0.1'
,
'dnsblQuery'
=>
'1.0.0.127.dnsbl.test'
,
'dnsblResponse'
=>
$dnsblFound
,
'whitelist'
=>
[],
'checkWhitelist'
=>
false
,
],
true
,
],
'IP is not blacklisted'
=>
[
[
'blacklist'
=>
[
'dnsbl.test'
],
'ip'
=>
'1.2.3.4'
,
'dnsblQuery'
=>
'4.3.2.1.dnsbl.test'
,
'dnsblResponse'
=>
$dnsblNotFound
,
'whitelist'
=>
[],
'checkWhitelist'
=>
false
,
],
false
,
],
'Blacklist is empty'
=>
[
[
'blacklist'
=>
[],
'ip'
=>
'127.0.0.1'
,
'dnsblQuery'
=>
'1.0.0.127.dnsbl.test'
,
'dnsblResponse'
=>
$dnsblFound
,
'whitelist'
=>
[],
'checkWhitelist'
=>
false
,
],
false
,
],
'IP is blacklisted and whitelisted; whitelist is not checked'
=>
[
[
'blacklist'
=>
[
'dnsbl.test'
],
'ip'
=>
'127.0.0.1'
,
'dnsblQuery'
=>
'1.0.0.127.dnsbl.test'
,
'dnsblResponse'
=>
$dnsblFound
,
'whitelist'
=>
[
'127.0.0.1'
],
'checkWhitelist'
=>
false
,
],
true
,
],
'IP is blacklisted and whitelisted; whitelist is checked'
=>
[
[
'blacklist'
=>
[
'dnsbl.test'
],
'ip'
=>
'127.0.0.1'
,
'dnsblQuery'
=>
'1.0.0.127.dnsbl.test'
,
'dnsblResponse'
=>
$dnsblFound
,
'whitelist'
=>
[
'127.0.0.1'
],
'checkWhitelist'
=>
true
,
],
false
,
],
];
}
public
function
testGetUniqueBlocks
()
{
$blockId
=
100
;
$block
=
$this
->
getMockBuilder
(
DatabaseBlock
::
class
)
->
onlyMethods
(
[
'getId'
]
)
->
getMock
();
$block
->
method
(
'getId'
)
->
willReturn
(
$blockId
);
$autoblock
=
$this
->
getMockBuilder
(
DatabaseBlock
::
class
)
->
onlyMethods
(
[
'getParentBlockId'
,
'getType'
]
)
->
getMock
();
$autoblock
->
method
(
'getParentBlockId'
)
->
willReturn
(
$blockId
);
$autoblock
->
method
(
'getType'
)
->
willReturn
(
Block
::
TYPE_AUTO
);
$autoblockWithoutParentIdMethod
=
$this
->
getMockBuilder
(
AbstractBlock
::
class
)
->
onlyMethods
(
[
'getType'
]
)
->
getMockForAbstractClass
();
$autoblockWithoutParentIdMethod
->
method
(
'getType'
)
->
willReturn
(
Block
::
TYPE_AUTO
);
$systemBlock
=
new
SystemBlock
();
$blocks
=
[
$block
,
$block
,
$autoblock
,
$systemBlock
,
$autoblockWithoutParentIdMethod
];
$blockManager
=
TestingAccessWrapper
::
newFromObject
(
$this
->
getBlockManager
(
[]
)
);
$this
->
assertArrayEquals
(
[
$block
,
$systemBlock
,
$autoblockWithoutParentIdMethod
],
$blockManager
->
getUniqueBlocks
(
$blocks
)
);
}
/**
* @dataProvider provideTrackBlockWithCookie
*/
public
function
testTrackBlockWithCookie
(
$options
,
$expected
)
{
$this
->
overrideConfigValue
(
MainConfigNames
::
CookiePrefix
,
''
);
if
(
is_int
(
$options
[
'block'
]
)
)
{
$options
[
'block'
]
=
$this
->
getTrackableBlock
(
$options
[
'block'
]
);
}
elseif
(
is_array
(
$options
[
'block'
]
)
)
{
$blocks
=
[];
foreach
(
$options
[
'block'
]
as
$block
)
{
if
(
is_int
(
$block
)
)
{
$blocks
[]
=
$this
->
getTrackableBlock
(
$block
);
}
elseif
(
$block
===
'system'
)
{
$blocks
[]
=
new
SystemBlock
();
}
}
$options
[
'block'
]
=
new
CompositeBlock
(
[
'originalBlocks'
=>
$blocks
]
);
}
$request
=
new
FauxRequest
();
if
(
$options
[
'cookieSet'
]
)
{
$request
->
setCookie
(
'BlockID'
,
'the value does not matter'
);
}
/** @var FauxResponse $response */
$response
=
$request
->
response
();
$user
=
$this
->
getMockBuilder
(
User
::
class
)
->
onlyMethods
(
[
'getBlock'
,
'getRequest'
]
)
->
getMock
();
$user
->
method
(
'getBlock'
)
->
willReturn
(
$options
[
'block'
]
);
$user
->
method
(
'getRequest'
)
->
willReturn
(
$request
);
// Although the block cookie is set via DeferredUpdates, in command line mode updates are
// processed immediately
$blockManager
=
$this
->
getBlockManager
(
[
MainConfigNames
::
SecretKey
=>
''
,
MainConfigNames
::
CookieSetOnIpBlock
=>
true
,
]
);
$blockManager
->
trackBlockWithCookie
(
$user
,
$response
);
$this
->
assertCount
(
$expected
[
'count'
],
$response
->
getCookies
()
);
$this
->
assertEquals
(
$expected
[
'value'
],
$response
->
getCookie
(
'BlockID'
)
);
}
public
static
function
provideTrackBlockWithCookie
()
{
$blockId
=
123
;
return
[
'Block cookie is already set; there is a trackable block'
=>
[
[
'cookieSet'
=>
true
,
'block'
=>
$blockId
,
],
[
'count'
=>
1
,
'value'
=>
$blockId
,
]
],
'Block cookie is already set; there is no block'
=>
[
[
'cookieSet'
=>
true
,
'block'
=>
null
,
],
[
// Cookie is cleared by setting it to empty value
'count'
=>
1
,
'value'
=>
''
,
]
],
'Block cookie is not yet set; there is no block'
=>
[
[
'cookieSet'
=>
false
,
'block'
=>
null
,
],
[
'count'
=>
0
,
'value'
=>
null
,
]
],
'Block cookie is not yet set; there is a trackable block'
=>
[
[
'cookieSet'
=>
false
,
'block'
=>
$blockId
,
],
[
'count'
=>
1
,
'value'
=>
$blockId
,
]
],
'Block cookie is not yet set; there is a composite block with a trackable block'
=>
[
[
'cookieSet'
=>
false
,
'block'
=>
[
'system'
,
$blockId
,
],
],
[
'count'
=>
1
,
'value'
=>
$blockId
,
]
],
'Block cookie is not yet set; there is a composite block but no trackable block'
=>
[
[
'cookieSet'
=>
false
,
'block'
=>
[
'system'
,
'system'
,
],
],
[
'count'
=>
0
,
'value'
=>
null
,
]
],
];
}
private
function
getTrackableBlock
(
$blockId
)
{
$block
=
$this
->
getMockBuilder
(
DatabaseBlock
::
class
)
->
onlyMethods
(
[
'getType'
,
'getId'
]
)
->
getMock
();
$block
->
method
(
'getType'
)
->
willReturn
(
DatabaseBlock
::
TYPE_IP
);
$block
->
method
(
'getId'
)
->
willReturn
(
$blockId
);
return
$block
;
}
/**
* @dataProvider provideSetBlockCookie
*/
public
function
testSetBlockCookie
(
$expiryDelta
,
$expectedExpiryDelta
)
{
$this
->
overrideConfigValue
(
MainConfigNames
::
CookiePrefix
,
''
);
$request
=
new
FauxRequest
();
$response
=
$request
->
response
();
/** @var BlockManager $blockManager */
$blockManager
=
TestingAccessWrapper
::
newFromObject
(
$this
->
getBlockManager
(
[
MainConfigNames
::
SecretKey
=>
''
,
MainConfigNames
::
CookieSetOnIpBlock
=>
true
,
]
)
);
$now
=
wfTimestamp
();
$block
=
new
DatabaseBlock
(
[
'expiry'
=>
$expiryDelta
===
''
?
''
:
$now
+
$expiryDelta
]
);
$blockManager
->
setBlockCookie
(
$block
,
$response
);
$cookies
=
$response
->
getCookies
();
$this
->
assertEqualsWithDelta
(
$now
+
$expectedExpiryDelta
,
$cookies
[
'BlockID'
][
'expire'
],
60
// Allow actual to be up to 60 seconds later than expected
);
}
public
static
function
provideSetBlockCookie
()
{
// Maximum length of a block cookie, defined in BlockManager::setBlockCookie
$maxExpiryDelta
=
(
24
*
60
*
60
);
$longExpiryDelta
=
(
48
*
60
*
60
);
$shortExpiryDelta
=
(
12
*
60
*
60
);
return
[
'Block has indefinite expiry'
=>
[
''
,
$maxExpiryDelta
,
],
'Block expiry is later than maximum cookie block expiry'
=>
[
$longExpiryDelta
,
$maxExpiryDelta
,
],
'Block expiry is sooner than maximum cookie block expiry'
=>
[
$shortExpiryDelta
,
$shortExpiryDelta
,
],
];
}
/**
* @dataProvider provideShouldTrackBlockWithCookie
*/
public
function
testShouldTrackBlockWithCookie
(
$options
,
$expected
)
{
$block
=
$this
->
getMockBuilder
(
DatabaseBlock
::
class
)
->
onlyMethods
(
[
'getType'
,
'isAutoblocking'
]
)
->
getMock
();
$block
->
method
(
'getType'
)
->
willReturn
(
$options
[
'type'
]
);
if
(
isset
(
$options
[
'autoblocking'
]
)
)
{
$block
->
method
(
'isAutoblocking'
)
->
willReturn
(
$options
[
'autoblocking'
]
);
}
/** @var BlockManager $blockManager */
$blockManager
=
TestingAccessWrapper
::
newFromObject
(
$this
->
getBlockManager
(
$options
[
'blockManagerConfig'
]
)
);
$this
->
assertSame
(
$expected
,
$blockManager
->
shouldTrackBlockWithCookie
(
$block
,
$options
[
'isAnon'
]
)
);
}
public
static
function
provideShouldTrackBlockWithCookie
()
{
return
[
'IP block, anonymous user, IP block cookies enabled'
=>
[
[
'type'
=>
DatabaseBlock
::
TYPE_IP
,
'isAnon'
=>
true
,
'blockManagerConfig'
=>
[
MainConfigNames
::
CookieSetOnIpBlock
=>
true
],
],
true
],
'IP range block, anonymous user, IP block cookies enabled'
=>
[
[
'type'
=>
DatabaseBlock
::
TYPE_RANGE
,
'isAnon'
=>
true
,
'blockManagerConfig'
=>
[
MainConfigNames
::
CookieSetOnIpBlock
=>
true
],
],
true
],
'IP block, anonymous user, IP block cookies disabled'
=>
[
[
'type'
=>
DatabaseBlock
::
TYPE_IP
,
'isAnon'
=>
true
,
'blockManagerConfig'
=>
[
MainConfigNames
::
CookieSetOnIpBlock
=>
false
],
],
false
],
'IP block, logged in user, IP block cookies enabled'
=>
[
[
'type'
=>
DatabaseBlock
::
TYPE_IP
,
'isAnon'
=>
false
,
'blockManagerConfig'
=>
[
MainConfigNames
::
CookieSetOnIpBlock
=>
true
],
],
false
],
'User block, anonymous, autoblock cookies enabled, block is autoblocking'
=>
[
[
'type'
=>
DatabaseBlock
::
TYPE_USER
,
'isAnon'
=>
true
,
'blockManagerConfig'
=>
[
MainConfigNames
::
CookieSetOnAutoblock
=>
true
],
'autoblocking'
=>
true
,
],
false
],
'User block, logged in, autoblock cookies enabled, block is autoblocking'
=>
[
[
'type'
=>
DatabaseBlock
::
TYPE_USER
,
'isAnon'
=>
false
,
'blockManagerConfig'
=>
[
MainConfigNames
::
CookieSetOnAutoblock
=>
true
],
'autoblocking'
=>
true
,
],
true
],
'User block, logged in, autoblock cookies disabled, block is autoblocking'
=>
[
[
'type'
=>
DatabaseBlock
::
TYPE_USER
,
'isAnon'
=>
false
,
'blockManagerConfig'
=>
[
MainConfigNames
::
CookieSetOnAutoblock
=>
false
],
'autoblocking'
=>
true
,
],
false
],
'User block, logged in, autoblock cookies enabled, block is not autoblocking'
=>
[
[
'type'
=>
DatabaseBlock
::
TYPE_USER
,
'isAnon'
=>
false
,
'blockManagerConfig'
=>
[
MainConfigNames
::
CookieSetOnAutoblock
=>
true
],
'autoblocking'
=>
false
,
],
false
],
'Block type is autoblock'
=>
[
[
'type'
=>
DatabaseBlock
::
TYPE_AUTO
,
'isAnon'
=>
true
,
'blockManagerConfig'
=>
[],
],
false
]
];
}
public
function
testClearBlockCookie
()
{
$this
->
overrideConfigValue
(
MainConfigNames
::
CookiePrefix
,
''
);
$request
=
new
FauxRequest
();
$response
=
$request
->
response
();
$response
->
setCookie
(
'BlockID'
,
'100'
);
$this
->
assertSame
(
'100'
,
$response
->
getCookie
(
'BlockID'
)
);
BlockManager
::
clearBlockCookie
(
$response
);
$this
->
assertSame
(
''
,
$response
->
getCookie
(
'BlockID'
)
);
}
/**
* @dataProvider provideGetIdFromCookieValue
*/
public
function
testGetIdFromCookieValue
(
$options
,
$expected
)
{
/** @var BlockManager $blockManager */
$blockManager
=
TestingAccessWrapper
::
newFromObject
(
$this
->
getBlockManager
(
[
MainConfigNames
::
SecretKey
=>
$options
[
'secretKey'
]
]
)
);
$this
->
assertEquals
(
$expected
,
$blockManager
->
getIdFromCookieValue
(
$options
[
'cookieValue'
]
)
);
}
public
static
function
provideGetIdFromCookieValue
()
{
$blockId
=
100
;
$secretKey
=
'123'
;
$hmac
=
MWCryptHash
::
hmac
(
$blockId
,
$secretKey
,
false
);
return
[
'No secret key is set'
=>
[
[
'secretKey'
=>
''
,
'cookieValue'
=>
$blockId
,
'calculatedHmac'
=>
MWCryptHash
::
hmac
(
$blockId
,
''
,
false
),
],
$blockId
,
],
'Secret key is set and stored hmac is correct'
=>
[
[
'secretKey'
=>
$secretKey
,
'cookieValue'
=>
$blockId
.
'!'
.
$hmac
,
'calculatedHmac'
=>
$hmac
,
],
$blockId
,
],
'Secret key is set and stored hmac is incorrect'
=>
[
[
'secretKey'
=>
$secretKey
,
'cookieValue'
=>
$blockId
.
'!xyz'
,
'calculatedHmac'
=>
$hmac
,
],
null
,
],
];
}
/**
* @dataProvider provideGetCookieValue
*/
public
function
testGetCookieValue
(
$options
,
$expected
)
{
/** @var BlockManager $blockManager */
$blockManager
=
TestingAccessWrapper
::
newFromObject
(
$this
->
getBlockManager
(
[
MainConfigNames
::
SecretKey
=>
$options
[
'secretKey'
]
]
)
);
$block
=
$this
->
getMockBuilder
(
DatabaseBlock
::
class
)
->
onlyMethods
(
[
'getId'
]
)
->
getMock
();
$block
->
method
(
'getId'
)
->
willReturn
(
$options
[
'blockId'
]
);
$this
->
assertEquals
(
$expected
,
$blockManager
->
getCookieValue
(
$block
)
);
}
public
static
function
provideGetCookieValue
()
{
$blockId
=
100
;
return
[
'Secret key not set'
=>
[
[
'secretKey'
=>
''
,
'blockId'
=>
$blockId
,
'hmac'
=>
MWCryptHash
::
hmac
(
$blockId
,
''
,
false
),
],
$blockId
,
],
'Secret key set'
=>
[
[
'secretKey'
=>
'123'
,
'blockId'
=>
$blockId
,
'hmac'
=>
MWCryptHash
::
hmac
(
$blockId
,
'123'
,
false
),
],
$blockId
.
'!'
.
MWCryptHash
::
hmac
(
$blockId
,
'123'
,
false
)
],
];
}
/**
* @dataProvider provideGetXffBlocks
*/
public
function
testGetXffBlocks
(
$applyIpBlocksToXff
,
$proxyWhiteList
,
$isAnon
,
$expected
)
{
$xff
=
'1.2.3.4, 5.6.7.8, 9.10.11.12'
;
$ip
=
'1.2.3.4'
;
$blockManagerConfig
=
[
MainConfigNames
::
ApplyIpBlocksToXff
=>
$applyIpBlocksToXff
,
MainConfigNames
::
ProxyWhitelist
=>
$proxyWhiteList
,
];
$blockManagerMock
=
$this
->
getMockBuilder
(
BlockManager
::
class
)
->
setConstructorArgs
(
$this
->
getBlockManagerConstructorArgs
(
$blockManagerConfig
)
)
->
onlyMethods
(
[
'getBlocksForIPList'
]
)
->
getMock
();
$blockManagerMock
->
method
(
'getBlocksForIPList'
)
->
willReturnCallback
(
function
()
use
(
$isAnon
)
{
if
(
$isAnon
)
{
return
[
$this
->
createMock
(
DatabaseBlock
::
class
)
];
}
else
{
return
[];
}
}
);
/** @var BlockManager $blockManager */
$blockManager
=
TestingAccessWrapper
::
newFromObject
(
$blockManagerMock
);
$this
->
assertSame
(
$expected
,
(
bool
)
$blockManager
->
getXffBlocks
(
$ip
,
$xff
,
$isAnon
,
false
)
);
}
public
static
function
provideGetXffBlocks
()
{
return
[
'ApplyIpBlocksToXff config is false'
=>
[
'applyIpBlocksToXff'
=>
false
,
'proxyWhiteList'
=>
[],
'isAnon'
=>
true
,
false
,
],
'IP is in ProxyWhiteList'
=>
[
'applyIpBlocksToXff'
=>
true
,
'proxyWhiteList'
=>
[
'1.2.3.4'
],
'isAnon'
=>
true
,
false
,
],
'User is logged in'
=>
[
'applyIpBlocksToXff'
=>
true
,
'proxyWhiteList'
=>
[],
'isAnon'
=>
false
,
false
,
],
'IP is in XFF list but not in ProxyWhiteList'
=>
[
'applyIpBlocksToXff'
=>
true
,
'proxyWhiteList'
=>
[],
'isAnon'
=>
true
,
true
,
],
];
}
/**
* @dataProvider provideGetSystemIpBlocks
*/
public
function
testGetSystemIpBlocks
(
$proxyWhitelist
,
$softBlockRanges
,
$isLocallyBlockedProxy
,
$isDnsBlacklisted
,
$isAnon
,
$expected
)
{
$ip
=
'1.2.3.4'
;
$blockManagerConfig
=
[
MainConfigNames
::
ProxyWhitelist
=>
$proxyWhitelist
,
MainConfigNames
::
SoftBlockRanges
=>
$softBlockRanges
,
MainConfigNames
::
ProxyList
=>
(
$isLocallyBlockedProxy
?
[
$ip
]
:
[]
),
];
$blockManagerMock
=
$this
->
getMockBuilder
(
BlockManager
::
class
)
->
setConstructorArgs
(
$this
->
getBlockManagerConstructorArgs
(
$blockManagerConfig
)
)
->
onlyMethods
(
[
'isDnsBlacklisted'
]
)
->
getMock
();
$blockManagerMock
->
method
(
'isDnsBlacklisted'
)
->
willReturn
(
$isDnsBlacklisted
);
/** @var BlockManager $blockManager */
$blockManager
=
TestingAccessWrapper
::
newFromObject
(
$blockManagerMock
);
$this
->
assertSame
(
$expected
,
(
bool
)
$blockManager
->
getSystemIpBlocks
(
$ip
,
$isAnon
)
);
}
public
static
function
provideGetSystemIpBlocks
()
{
return
[
'IP is in ProxyWhiteList'
=>
[
'proxyWhitelist'
=>
[
'1.2.3.4'
],
'softBlockRanges'
=>
[],
'isLocallyBlockedProxy'
=>
true
,
'isDnsBlacklisted'
=>
true
,
'isAnon'
=>
true
,
false
,
],
'IP is locally blocked proxy only'
=>
[
'proxyWhitelist'
=>
[],
'softBlockRanges'
=>
[],
'isLocallyBlockedProxy'
=>
true
,
'isDnsBlacklisted'
=>
false
,
'isAnon'
=>
false
,
true
,
],
'IP is DNS blacklisted only, anon'
=>
[
'proxyWhitelist'
=>
[],
'softBlockRanges'
=>
[],
'isLocallyBlockedProxy'
=>
false
,
'isDnsBlacklisted'
=>
true
,
'isAnon'
=>
true
,
true
,
],
'IP is DNS blacklisted only, logged in'
=>
[
'proxyWhitelist'
=>
[],
'softBlockRanges'
=>
[],
'isLocallyBlockedProxy'
=>
false
,
'isDnsBlacklisted'
=>
true
,
'isAnon'
=>
false
,
false
,
],
'IP is in SoftBlockRanges and ProxyWhiteList, anon'
=>
[
'proxyWhitelist'
=>
[
'1.2.3.4'
],
'softBlockRanges'
=>
[
'1.2.3.4'
],
'isLocallyBlockedProxy'
=>
false
,
'isDnsBlacklisted'
=>
false
,
'isAnon'
=>
true
,
true
,
],
'IP is in SoftBlockRanges and ProxyWhiteList, logged in'
=>
[
'proxyWhitelist'
=>
[
'1.2.3.4'
],
'softBlockRanges'
=>
[
'1.2.3.4'
],
'isLocallyBlockedProxy'
=>
false
,
'isDnsBlacklisted'
=>
false
,
'isAnon'
=>
false
,
false
,
],
];
}
public
function
testGetBlocksForIPList
()
{
$blockManager
=
$this
->
getBlockManager
(
[]
);
$block
=
$this
->
getServiceContainer
()
->
getDatabaseBlockStore
()
->
insertBlockWithParams
(
[
'address'
=>
'1.2.3.4'
,
'by'
=>
$this
->
getTestSysop
()->
getUser
(),
]
);
// Early return of empty array if no ips in the list
$list
=
$blockManager
->
getBlocksForIPList
(
[],
true
,
false
);
$this
->
assertCount
(
0
,
$list
,
'No blocks retrieved if no ips listed'
);
// Early return of empty array if all ips are either invalid or trusted proxies,
// '192.168.1.1' is set to trusted in setUp();
$list
=
$blockManager
->
getBlocksForIPList
(
[
'300.300.300.300'
,
'192.168.1.1'
],
true
,
false
);
$this
->
assertCount
(
0
,
$list
,
'No blocks retrieved if all ips are invalid or trusted proxies'
);
// Actually fetching, block was inserted above
$list
=
$blockManager
->
getBlocksForIPList
(
[
'1.2.3.4'
],
true
,
false
);
$this
->
assertCount
(
1
,
$list
,
'Block retrieved for the blocked ip'
);
$this
->
assertInstanceOf
(
DatabaseBlock
::
class
,
$list
[
0
],
'DatabaseBlock returned'
);
$this
->
assertSame
(
$block
->
getId
(),
$list
[
0
]->
getId
(),
'Block returned is the correct one'
);
}
/**
* @coversNothing
*/
public
function
testAllServiceOptionsUsed
()
{
$this
->
assertAllServiceOptionsUsed
();
}
/**
* Test ported from DatabaseBlock
*/
public
function
testBlockedUserCanNotCreateAccount
()
{
$username
=
'BlockedUserToCreateAccountWith'
;
$u
=
User
::
createNew
(
$username
);
$userId
=
$u
->
getId
();
$this
->
assertNotEquals
(
0
,
$userId
,
'Check user id is not 0'
);
TestUser
::
setPasswordForUser
(
$u
,
'NotRandomPass'
);
unset
(
$u
);
$blockStore
=
$this
->
getServiceContainer
()->
getDatabaseBlockStore
();
$this
->
assertNull
(
$blockStore
->
newFromTarget
(
$username
),
"$username should not be blocked"
);
// Reload user
$userFactory
=
$this
->
getServiceContainer
()->
getUserFactory
();
$u
=
$userFactory
->
newFromName
(
$username
);
$this
->
assertTrue
(
$u
->
isDefinitelyAllowed
(
'createaccount'
),
"Our sandbox user should be able to create account before being blocked"
);
// Foreign perspective (blockee not on current wiki)...
$block
=
$blockStore
->
insertBlockWithParams
(
[
'address'
=>
$username
,
'reason'
=>
'crosswiki block...'
,
'timestamp'
=>
wfTimestampNow
(),
'expiry'
=>
$this
->
getDb
()->
getInfinity
(),
'createAccount'
=>
true
,
'enableAutoblock'
=>
true
,
'hideName'
=>
true
,
'blockEmail'
=>
true
,
'by'
=>
UserIdentityValue
::
newExternal
(
'm'
,
'MetaWikiUser'
),
]
);
// Reload block from DB
$userBlock
=
$blockStore
->
newFromTarget
(
$username
);
$this
->
assertTrue
(
(
bool
)
$block
->
appliesToRight
(
'createaccount'
),
"Block object in DB should block right 'createaccount'"
);
$this
->
assertInstanceOf
(
DatabaseBlock
::
class
,
$userBlock
,
"'$username' block block object should be existent"
);
// Reload user
$u
=
$userFactory
->
newFromName
(
$username
);
$this
->
assertFalse
(
$u
->
isDefinitelyAllowed
(
'createaccount'
),
"Our sandbox user '$username' should NOT be able to create account"
);
}
public
static
function
providerXff
()
{
return
[
[
'xff'
=>
'1.2.3.4, 70.2.1.1, 60.2.1.1, 2.3.4.5'
,
'count'
=>
2
,
'result'
=>
'Range Hardblock'
],
[
'xff'
=>
'1.2.3.4, 50.2.1.1, 60.2.1.1, 2.3.4.5'
,
'count'
=>
2
,
'result'
=>
'Range Softblock with AC Disabled'
],
[
'xff'
=>
'1.2.3.4, 70.2.1.1, 50.1.1.1, 2.3.4.5'
,
'count'
=>
2
,
'result'
=>
'Exact Softblock'
],
[
'xff'
=>
'1.2.3.4, 70.2.1.1, 50.2.1.1, 50.1.1.1, 2.3.4.5'
,
'count'
=>
3
,
'result'
=>
'Exact Softblock'
],
[
'xff'
=>
'1.2.3.4, 70.2.1.1, 50.2.1.1, 2.3.4.5'
,
'count'
=>
2
,
'result'
=>
'Range Hardblock'
],
[
'xff'
=>
'1.2.3.4, 70.2.1.1, 60.2.1.1, 2.3.4.5'
,
'count'
=>
2
,
'result'
=>
'Range Hardblock'
],
[
'xff'
=>
'50.2.1.1, 60.2.1.1, 2.3.4.5'
,
'count'
=>
2
,
'result'
=>
'Range Softblock with AC Disabled'
],
[
'xff'
=>
'1.2.3.4, 50.1.1.1, 60.2.1.1, 2.3.4.5'
,
'count'
=>
2
,
'result'
=>
'Exact Softblock'
],
[
'xff'
=>
'1.2.3.4, <$A_BUNCH-OF{INVALID}TEXT
\>
, 60.2.1.1, 2.3.4.5'
,
'count'
=>
1
,
'result'
=>
'Range Softblock with AC Disabled'
],
[
'xff'
=>
'1.2.3.4, 50.2.1.1, 2001:4860:4001:802::1003, 2.3.4.5'
,
'count'
=>
2
,
'result'
=>
'Range6 Hardblock'
],
];
}
/**
* @dataProvider providerXff
*/
public
function
testBlocksOnXff
(
$xff
,
$exCount
,
$exResult
)
{
$this
->
setupForXff
();
$this
->
getServiceContainer
()->
getDatabaseBlockStore
()
->
insertBlockWithParams
(
[
'targetUser'
=>
$this
->
getTestUser
()->
getUserIdentity
(),
'by'
=>
$this
->
getTestSysop
()->
getUserIdentity
()
]
);
$list
=
array_map
(
'trim'
,
explode
(
','
,
$xff
)
);
$manager
=
$this
->
getBlockManager
(
[]
);
$xffblocks
=
$manager
->
getBlocksForIPList
(
$list
,
true
,
false
);
$this
->
assertCount
(
$exCount
,
$xffblocks
,
'Number of blocks for '
.
$xff
);
}
private
function
setupForXff
()
{
$blockList
=
[
[
'target'
=>
'70.2.0.0/16'
,
'type'
=>
DatabaseBlock
::
TYPE_RANGE
,
'desc'
=>
'Range Hardblock'
,
'ACDisable'
=>
false
,
'isHardblock'
=>
true
,
'isAutoBlocking'
=>
false
,
],
[
'target'
=>
'2001:4860:4001:0:0:0:0:0/48'
,
'type'
=>
DatabaseBlock
::
TYPE_RANGE
,
'desc'
=>
'Range6 Hardblock'
,
'ACDisable'
=>
false
,
'isHardblock'
=>
true
,
'isAutoBlocking'
=>
false
,
],
[
'target'
=>
'60.2.0.0/16'
,
'type'
=>
DatabaseBlock
::
TYPE_RANGE
,
'desc'
=>
'Range Softblock with AC Disabled'
,
'ACDisable'
=>
true
,
'isHardblock'
=>
false
,
'isAutoBlocking'
=>
false
,
],
[
'target'
=>
'50.2.0.0/16'
,
'type'
=>
DatabaseBlock
::
TYPE_RANGE
,
'desc'
=>
'Range Softblock'
,
'ACDisable'
=>
false
,
'isHardblock'
=>
false
,
'isAutoBlocking'
=>
false
,
],
[
'target'
=>
'50.1.1.1'
,
'type'
=>
DatabaseBlock
::
TYPE_IP
,
'desc'
=>
'Exact Softblock'
,
'ACDisable'
=>
false
,
'isHardblock'
=>
false
,
'isAutoBlocking'
=>
false
,
],
];
$targetFactory
=
$this
->
getServiceContainer
()->
getBlockTargetFactory
();
$blockStore
=
$this
->
getServiceContainer
()->
getDatabaseBlockStore
();
$blocker
=
$this
->
getTestUser
()->
getUser
();
foreach
(
$blockList
as
$insBlock
)
{
$block
=
new
DatabaseBlock
();
$block
->
setTarget
(
$targetFactory
->
newFromString
(
$insBlock
[
'target'
]
)
);
$block
->
setBlocker
(
$blocker
);
$block
->
setReason
(
$insBlock
[
'desc'
]
);
$block
->
setExpiry
(
'infinity'
);
$block
->
isCreateAccountBlocked
(
$insBlock
[
'ACDisable'
]
);
$block
->
isHardblock
(
$insBlock
[
'isHardblock'
]
);
$block
->
isAutoblocking
(
$insBlock
[
'isAutoBlocking'
]
);
$blockStore
->
insertBlock
(
$block
);
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Aug 19 2026, 19:37 (6 w, 6 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
2a/7c/47abe790459d6c8f31d74a5ab4ed
Default Alt Text
BlockManagerTest.php (31 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment