Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4152970
SpecialMergeAccount.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
SpecialMergeAccount.php
View Options
<?php
namespace
MediaWiki\Extension\CentralAuth\Special
;
use
Exception
;
use
InvalidArgumentException
;
use
MediaWiki\Exception\ErrorPageError
;
use
MediaWiki\Extension\CentralAuth\CentralAuthDatabaseManager
;
use
MediaWiki\Extension\CentralAuth\Config\CAMainConfigNames
;
use
MediaWiki\Extension\CentralAuth\User\CentralAuthUser
;
use
MediaWiki\Html\Html
;
use
MediaWiki\SpecialPage\SpecialPage
;
use
MediaWiki\Title\NamespaceInfo
;
use
MediaWiki\User\UserFactory
;
use
MediaWiki\WikiMap\WikiMap
;
use
MWCryptRand
;
use
RuntimeException
;
use
Wikimedia\AtEase\AtEase
;
class
SpecialMergeAccount
extends
SpecialPage
{
/** @var string */
protected
$mUserName
;
/** @var bool */
protected
$mAttemptMerge
;
/** @var string */
protected
$mMergeAction
;
/** @var string */
protected
$mPassword
;
/** @var string[] */
protected
$mWikiIDs
;
/** @var string */
protected
$mSessionToken
;
/** @var string */
protected
$mSessionKey
;
private
NamespaceInfo
$namespaceInfo
;
private
UserFactory
$userFactory
;
private
CentralAuthDatabaseManager
$databaseManager
;
public
function
__construct
(
NamespaceInfo
$namespaceInfo
,
UserFactory
$userFactory
,
CentralAuthDatabaseManager
$databaseManager
)
{
parent
::
__construct
(
'MergeAccount'
,
'centralauth-merge'
);
$this
->
namespaceInfo
=
$namespaceInfo
;
$this
->
userFactory
=
$userFactory
;
$this
->
databaseManager
=
$databaseManager
;
}
/** @inheritDoc */
public
function
doesWrites
()
{
return
true
;
}
/** @inheritDoc */
public
function
execute
(
$subpage
)
{
$this
->
setHeaders
();
$this
->
addHelpLink
(
'Extension:CentralAuth'
);
$this
->
getOutput
()->
addModuleStyles
(
'mediawiki.codex.messagebox.styles'
);
if
(
$subpage
!==
null
&&
preg_match
(
"/^[0-9a-zA-Z]{32}$/"
,
$subpage
)
)
{
$user
=
$this
->
userFactory
->
newFromConfirmationCode
(
$subpage
);
if
(
is_object
(
$user
)
)
{
$user
->
confirmEmail
();
$user
->
saveSettings
();
$this
->
getOutput
()->
addWikiMsg
(
'confirmemail_success'
);
}
else
{
$this
->
getOutput
()->
addWikiMsg
(
'confirmemail_invalid'
);
// return; // Let's be greedy and still show them MergeAccount
}
}
if
(
!
$this
->
userCanExecute
(
$this
->
getUser
()
)
)
{
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-merge-denied'
);
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-readmore-text'
);
return
;
}
if
(
!
$this
->
getUser
()->
isNamed
()
)
{
$loginpage
=
SpecialPage
::
getTitleFor
(
'Userlogin'
);
$loginurl
=
$loginpage
->
getFullUrl
(
[
'returnto'
=>
$this
->
getPageTitle
()->
getPrefixedText
()
]
);
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-merge-notlogged'
,
$loginurl
);
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-readmore-text'
);
return
;
}
$this
->
databaseManager
->
assertNotReadOnly
();
$request
=
$this
->
getRequest
();
$this
->
mUserName
=
$this
->
getUser
()->
getName
();
$this
->
mAttemptMerge
=
$request
->
wasPosted
();
$this
->
mMergeAction
=
$request
->
getVal
(
'wpMergeAction'
);
$this
->
mPassword
=
$request
->
getVal
(
'wpPassword'
);
$this
->
mWikiIDs
=
$request
->
getArray
(
'wpWikis'
);
$this
->
mSessionToken
=
$request
->
getVal
(
'wpMergeSessionToken'
);
$this
->
mSessionKey
=
pack
(
"H*"
,
$request
->
getVal
(
'wpMergeSessionKey'
)
);
// Possible demo states
// success, all accounts merged
// successful login, some accounts merged, others left
// successful login, others left
// not account owner, others left
// is owner / is not owner
// did / did not merge some accounts
// do / don't have more accounts to merge
if
(
$this
->
mAttemptMerge
)
{
// First check the edit token
if
(
!
$this
->
getUser
()->
matchEditToken
(
$request
->
getVal
(
'wpEditToken'
)
)
)
{
throw
new
ErrorPageError
(
'sessionfailure-title'
,
'sessionfailure'
);
}
switch
(
$this
->
mMergeAction
)
{
case
"dryrun"
:
$this
->
doDryRunMerge
();
break
;
case
"initial"
:
$this
->
doInitialMerge
();
break
;
case
"cleanup"
:
$this
->
doCleanupMerge
();
break
;
case
"attach"
:
$this
->
doAttachMerge
();
break
;
default
:
throw
new
InvalidArgumentException
(
'Invalid merge action '
.
$this
->
mMergeAction
.
' given'
);
}
return
;
}
$globalUser
=
CentralAuthUser
::
getInstanceByName
(
$this
->
mUserName
);
if
(
$globalUser
->
exists
()
)
{
$this
->
showFormForExistingUsers
(
$globalUser
);
}
else
{
$this
->
showWelcomeForm
();
}
}
/**
* Pick which form to show for a user that already exists
*/
private
function
showFormForExistingUsers
(
CentralAuthUser
$globalUser
)
{
if
(
$globalUser
->
isAttached
()
)
{
$this
->
showCleanupForm
();
}
else
{
$this
->
showAttachForm
();
}
}
/**
* To pass potentially multiple passwords from one form submission
* to another while previewing the merge behavior, we can store them
* in the server-side session information.
*
* We'd rather not have plaintext passwords floating about on disk
* or memcached, so the session store is obfuscated with simple XOR
* encryption. The key is passed in the form instead of the session
* data, so they won't be found floating in the same place.
*/
private
function
initSession
()
{
$this
->
mSessionToken
=
MWCryptRand
::
generateHex
(
32
);
$this
->
mSessionKey
=
random_bytes
(
128
);
}
/**
* @return string[]
*/
private
function
getWorkingPasswords
()
{
AtEase
::
suppressWarnings
();
$data
=
$this
->
getRequest
()->
getSessionData
(
'wsCentralAuthMigration'
);
$passwords
=
unserialize
(
gzinflate
(
$this
->
xorString
(
$data
[
$this
->
mSessionToken
],
$this
->
mSessionKey
)
)
);
AtEase
::
restoreWarnings
();
if
(
is_array
(
$passwords
)
)
{
return
$passwords
;
}
return
[];
}
/**
* @param string $password
*/
private
function
addWorkingPassword
(
$password
)
{
$passwords
=
$this
->
getWorkingPasswords
();
if
(
!
in_array
(
$password
,
$passwords
)
)
{
$passwords
[]
=
$password
;
}
// Lightly obfuscate the passwords while we're storing them,
// just to make us feel better about them floating around.
$request
=
$this
->
getRequest
();
$data
=
$request
->
getSessionData
(
'wsCentralAuthMigration'
);
$data
[
$this
->
mSessionToken
]
=
$this
->
xorString
(
gzdeflate
(
serialize
(
$passwords
)
),
$this
->
mSessionKey
);
$request
->
setSessionData
(
'wsCentralAuthMigration'
,
$data
);
}
private
function
clearWorkingPasswords
()
{
$request
=
$this
->
getRequest
();
$data
=
$request
->
getSessionData
(
'wsCentralAuthMigration'
);
unset
(
$data
[
$this
->
mSessionToken
]
);
$request
->
setSessionData
(
'wsCentralAuthMigration'
,
$data
);
}
/**
* @param string $text
* @param string $key
* @return string
*/
private
function
xorString
(
$text
,
$key
)
{
if
(
$key
!==
''
)
{
$textLen
=
strlen
(
$text
);
$keyLen
=
strlen
(
$key
);
for
(
$i
=
0
;
$i
<
$textLen
;
$i
++
)
{
$text
[
$i
]
=
chr
(
0xff
&
(
ord
(
$text
[
$i
]
)
^
ord
(
$key
[
$i
%
$keyLen
]
)
)
);
}
}
return
$text
;
}
private
function
doDryRunMerge
()
{
$globalUser
=
CentralAuthUser
::
getPrimaryInstance
(
$this
->
getUser
()
);
if
(
$globalUser
->
exists
()
)
{
// Already exists - race condition
$this
->
showFormForExistingUsers
(
$globalUser
);
return
;
}
if
(
$this
->
getConfig
()->
get
(
CAMainConfigNames
::
CentralAuthDryRun
)
)
{
$this
->
getOutput
()->
addHTML
(
Html
::
successBox
(
$this
->
msg
(
'centralauth-notice-dryrun'
)->
parseAsBlock
()
)
);
}
$password
=
$this
->
getRequest
()->
getVal
(
'wpPassword'
);
$this
->
addWorkingPassword
(
$password
);
$passwords
=
$this
->
getWorkingPasswords
();
$home
=
false
;
$attached
=
[];
$unattached
=
[];
$methods
=
[];
$status
=
$globalUser
->
migrationDryRun
(
$passwords
,
$home
,
$attached
,
$unattached
,
$methods
);
if
(
$status
->
isGood
()
)
{
// This is the global account or matched it
if
(
count
(
$unattached
)
==
0
)
{
// Everything matched -- very convenient!
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-merge-dryrun-complete'
);
}
else
{
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-merge-dryrun-incomplete'
);
}
if
(
count
(
$unattached
)
>
0
)
{
$this
->
getOutput
()->
addHTML
(
$this
->
step2PasswordForm
(
$unattached
)
);
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-merge-dryrun-or'
);
}
$subAttached
=
array_diff
(
$attached
,
[
$home
]
);
$this
->
getOutput
()->
addHTML
(
$this
->
step3ActionForm
(
$home
,
$subAttached
,
$methods
)
);
}
else
{
// Show error message from status
$out
=
$this
->
getOutput
();
foreach
(
$status
->
getMessages
()
as
$msg
)
{
$out
->
addHTML
(
Html
::
errorBox
(
$this
->
msg
(
$msg
)->
parse
()
)
);
}
// Show wiki list if required
if
(
$status
->
hasMessage
(
'centralauth-merge-home-password'
)
)
{
$out
=
Html
::
rawElement
(
'h2'
,
[],
$this
->
msg
(
'centralauth-list-home-title'
)->
escaped
()
);
$out
.=
$this
->
msg
(
'centralauth-list-home-dryrun'
)->
parseAsBlock
();
$out
.=
$this
->
listAttached
(
[
$home
],
[
$home
=>
'primary'
]
);
$this
->
getOutput
()->
addHTML
(
$out
);
}
// Show password box
$this
->
getOutput
()->
addHTML
(
$this
->
step1PasswordForm
()
);
}
}
private
function
doInitialMerge
()
{
$globalUser
=
CentralAuthUser
::
getPrimaryInstance
(
$this
->
getUser
()
);
if
(
$this
->
getConfig
()->
get
(
CAMainConfigNames
::
CentralAuthDryRun
)
)
{
$this
->
dryRunError
();
return
;
}
if
(
$globalUser
->
exists
()
)
{
// Already exists - race condition
$this
->
showFormForExistingUsers
(
$globalUser
);
return
;
}
$passwords
=
$this
->
getWorkingPasswords
();
if
(
!
$passwords
)
{
throw
new
RuntimeException
(
"Submission error -- invalid input"
);
}
$globalUser
->
storeAndMigrate
(
$passwords
,
true
,
false
,
true
);
$this
->
clearWorkingPasswords
();
$this
->
showCleanupForm
();
}
private
function
doCleanupMerge
()
{
$globalUser
=
CentralAuthUser
::
getPrimaryInstance
(
$this
->
getUser
()
);
if
(
!
$globalUser
->
exists
()
)
{
throw
new
RuntimeException
(
"User doesn't exist -- race condition?"
);
}
if
(
!
$globalUser
->
isAttached
()
)
{
throw
new
RuntimeException
(
"Can't cleanup merge if not already attached."
);
}
if
(
$this
->
getConfig
()->
get
(
CAMainConfigNames
::
CentralAuthDryRun
)
)
{
$this
->
dryRunError
();
return
;
}
$password
=
$this
->
getRequest
()->
getText
(
'wpPassword'
);
$attached
=
[];
$unattached
=
[];
$ok
=
$globalUser
->
attemptPasswordMigration
(
$password
,
$attached
,
$unattached
);
$this
->
clearWorkingPasswords
();
if
(
!
$ok
)
{
if
(
!
$attached
)
{
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-finish-noconfirms'
);
}
else
{
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-finish-incomplete'
);
}
}
$this
->
showCleanupForm
();
}
private
function
doAttachMerge
()
{
$globalUser
=
CentralAuthUser
::
getPrimaryInstance
(
$this
->
getUser
()
);
if
(
!
$globalUser
->
exists
()
)
{
throw
new
RuntimeException
(
"User doesn't exist -- race condition?"
);
}
if
(
$globalUser
->
isAttached
()
)
{
// Already attached - race condition
$this
->
showCleanupForm
();
return
;
}
if
(
$this
->
getConfig
()->
get
(
CAMainConfigNames
::
CentralAuthDryRun
)
)
{
$this
->
dryRunError
();
return
;
}
$password
=
$this
->
getRequest
()->
getText
(
'wpPassword'
);
if
(
$globalUser
->
authenticate
(
$password
)
==
[
CentralAuthUser
::
AUTHENTICATE_OK
]
)
{
$globalUser
->
attach
(
WikiMap
::
getCurrentWikiId
(),
'password'
);
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-attach-success'
);
$this
->
showCleanupForm
();
}
else
{
$this
->
getOutput
()->
addHTML
(
Html
::
errorBox
(
$this
->
msg
(
'wrongpassword'
)->
escaped
()
)
.
$this
->
attachActionForm
()
);
}
}
private
function
showWelcomeForm
()
{
if
(
$this
->
getConfig
()->
get
(
CAMainConfigNames
::
CentralAuthDryRun
)
)
{
$this
->
getOutput
()->
addHTML
(
Html
::
successBox
(
$this
->
msg
(
'centralauth-notice-dryrun'
)->
parseAsBlock
()
)
);
}
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-merge-welcome'
);
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-readmore-text'
);
$this
->
initSession
();
$this
->
getOutput
()->
addHTML
(
$this
->
passwordForm
(
'dryrun'
,
$this
->
msg
(
'centralauth-merge-step1-title'
)->
text
(),
$this
->
msg
(
'centralauth-merge-step1-detail'
)->
escaped
(),
$this
->
msg
(
'centralauth-merge-step1-submit'
)->
text
()
)
);
}
private
function
showCleanupForm
()
{
$globalUser
=
CentralAuthUser
::
getInstance
(
$this
->
getUser
()
);
$merged
=
$globalUser
->
listAttached
();
$remainder
=
$globalUser
->
listUnattached
();
$this
->
showStatus
(
$merged
,
$remainder
);
}
private
function
showAttachForm
()
{
$globalUser
=
CentralAuthUser
::
getInstance
(
$this
->
getUser
()
);
$merged
=
$globalUser
->
listAttached
();
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-attach-list-attached'
,
$this
->
mUserName
);
$this
->
getOutput
()->
addHTML
(
$this
->
listAttached
(
$merged
)
);
$this
->
getOutput
()->
addHTML
(
$this
->
attachActionForm
()
);
}
/**
* @param string[] $merged
* @param string[] $remainder
*/
private
function
showStatus
(
$merged
,
$remainder
)
{
$remainderCount
=
count
(
$remainder
);
if
(
$remainderCount
>
0
)
{
$this
->
getOutput
()->
setPageTitleMsg
(
$this
->
msg
(
'centralauth-incomplete'
)
);
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-incomplete-text'
);
}
else
{
$this
->
getOutput
()->
setPageTitleMsg
(
$this
->
msg
(
'centralauth-complete'
)
);
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-complete-text'
);
}
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-readmore-text'
);
if
(
$merged
)
{
$this
->
getOutput
()->
addHTML
(
Html
::
element
(
'hr'
)
);
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-list-attached'
,
$this
->
mUserName
,
count
(
$merged
)
);
$this
->
getOutput
()->
addHTML
(
$this
->
listAttached
(
$merged
)
);
}
if
(
$remainder
)
{
$this
->
getOutput
()->
addHTML
(
Html
::
element
(
'hr'
)
);
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-list-unattached'
,
$this
->
mUserName
,
$remainderCount
);
$this
->
getOutput
()->
addHTML
(
$this
->
listUnattached
(
$remainder
)
);
// Try the password form!
$this
->
getOutput
()->
addHTML
(
$this
->
passwordForm
(
'cleanup'
,
$this
->
msg
(
'centralauth-finish-title'
)->
text
(),
$this
->
msg
(
'centralauth-finish-text'
)->
parseAsBlock
(),
$this
->
msg
(
'centralauth-finish-login'
)->
text
()
)
);
}
}
/**
* @param string[] $wikiList
* @param string[] $methods
* @return string
*/
private
function
listAttached
(
$wikiList
,
$methods
=
[]
)
{
return
$this
->
listWikis
(
$wikiList
,
$methods
);
}
/**
* @param string[] $wikiList
* @return string
*/
private
function
listUnattached
(
$wikiList
)
{
return
$this
->
listWikis
(
$wikiList
);
}
/**
* @param string[] $list
* @param string[] $methods
* @return string
*/
private
function
listWikis
(
$list
,
$methods
=
[]
)
{
asort
(
$list
);
return
$this
->
formatList
(
$list
,
$methods
,
[
$this
,
'listWikiItem'
]
);
}
/**
* @param string[] $items
* @param string[] $methods
* @param callable $callback
* @return string
*/
private
function
formatList
(
$items
,
$methods
,
$callback
)
{
if
(
!
$items
)
{
return
''
;
}
$itemMethods
=
[];
foreach
(
$items
as
$item
)
{
$itemMethods
[]
=
$methods
[
$item
]
??
''
;
}
$html
=
Html
::
openElement
(
'ul'
)
.
"
\n
"
;
$list
=
array_map
(
$callback
,
$items
,
$itemMethods
);
foreach
(
$list
as
$item
)
{
$html
.=
Html
::
rawElement
(
'li'
,
[],
$item
)
.
"
\n
"
;
}
$html
.=
Html
::
closeElement
(
'ul'
)
.
"
\n
"
;
return
$html
;
}
/**
* @param string $wikiID
* @param string $method
* @return string
*/
private
function
listWikiItem
(
$wikiID
,
$method
)
{
$return
=
$this
->
foreignUserLink
(
$wikiID
);
if
(
$method
)
{
// Give grep a chance to find the usages:
// centralauth-merge-method-primary, centralauth-merge-method-empty,
// centralauth-merge-method-mail, centralauth-merge-method-password,
// centralauth-merge-method-admin, centralauth-merge-method-new,
// centralauth-merge-method-login,
$return
.=
$this
->
msg
(
'word-separator'
)->
escaped
();
$return
.=
$this
->
msg
(
'parentheses'
,
$this
->
msg
(
'centralauth-merge-method-'
.
$method
)->
text
()
)->
escaped
();
}
return
$return
;
}
/**
* @param string $wikiID
* @return string
* @throws Exception
*/
private
function
foreignUserLink
(
$wikiID
)
{
$wiki
=
WikiMap
::
getWiki
(
$wikiID
);
if
(
!
$wiki
)
{
throw
new
InvalidArgumentException
(
"Invalid wiki: $wikiID"
);
}
$wikiname
=
$wiki
->
getDisplayName
();
return
SpecialCentralAuth
::
foreignLink
(
$wiki
,
$this
->
namespaceInfo
->
getCanonicalName
(
NS_USER
)
.
':'
.
$this
->
mUserName
,
$wikiname
,
$this
->
msg
(
'centralauth-foreign-link'
,
$this
->
mUserName
,
$wikiname
)->
text
()
);
}
/**
* @param string $action Value for wpMergeAction hidden form field
* @param string $title Header for form (Plain text. Will be escaped by this method)
* @param string $text Raw html contents of form
* @return string HTML of form
*/
private
function
actionForm
(
$action
,
$title
,
$text
)
{
return
Html
::
openElement
(
'div'
,
[
'id'
=>
"userloginForm"
]
)
.
Html
::
openElement
(
'form'
,
[
'method'
=>
'post'
,
'action'
=>
$this
->
getPageTitle
()->
getLocalUrl
(
'action=submit'
)
]
)
.
Html
::
element
(
'h2'
,
[],
$title
)
.
Html
::
hidden
(
'wpEditToken'
,
$this
->
getUser
()->
getEditToken
()
)
.
Html
::
hidden
(
'wpMergeAction'
,
$action
)
.
Html
::
hidden
(
'wpMergeSessionToken'
,
$this
->
mSessionToken
)
.
Html
::
hidden
(
'wpMergeSessionKey'
,
bin2hex
(
$this
->
mSessionKey
)
)
.
$text
.
Html
::
closeElement
(
'form'
)
.
Html
::
element
(
'br'
,
[
'clear'
=>
'all'
]
)
.
Html
::
closeElement
(
'div'
);
}
/**
* @param string $action wpMergeAction form value
* @param string $title Header of form (Not html escaped)
* @param string $text Raw html contents of form
* @param string $submit Text of submit button (Not html escaped)
* @return string HTML of form.
*/
private
function
passwordForm
(
$action
,
$title
,
$text
,
$submit
)
{
$table
=
Html
::
rawElement
(
'table'
,
[],
Html
::
rawElement
(
'tr'
,
[],
Html
::
rawElement
(
'td'
,
[],
Html
::
label
(
$this
->
msg
(
'centralauth-finish-password'
)->
text
(),
'wpPassword1'
)
)
.
Html
::
rawElement
(
'td'
,
[],
Html
::
input
(
'wpPassword'
,
''
,
'text'
,
[
'type'
=>
'password'
,
'id'
=>
'wpPassword1'
,
'size'
=>
20
]
)
)
)
.
Html
::
rawElement
(
'tr'
,
[],
Html
::
rawElement
(
'td'
)
.
Html
::
rawElement
(
'td'
,
[],
Html
::
submitButton
(
$submit
,
[
'name'
=>
'wpLogin'
]
)
)
)
);
return
$this
->
actionForm
(
$action
,
$title
,
$text
.
$table
);
}
/**
* @return string
*/
private
function
step1PasswordForm
()
{
return
$this
->
passwordForm
(
'dryrun'
,
$this
->
msg
(
'centralauth-merge-step1-title'
)->
text
(),
$this
->
msg
(
'centralauth-merge-step1-detail'
)->
escaped
(),
$this
->
msg
(
'centralauth-merge-step1-submit'
)->
text
()
);
}
/**
* @param string[] $unattached
* @return string
*/
private
function
step2PasswordForm
(
$unattached
)
{
return
$this
->
passwordForm
(
'dryrun'
,
$this
->
msg
(
'centralauth-merge-step2-title'
)->
text
(),
$this
->
msg
(
'centralauth-merge-step2-detail'
,
$this
->
getUser
()->
getName
()
)->
parseAsBlock
()
.
$this
->
listUnattached
(
$unattached
),
$this
->
msg
(
'centralauth-merge-step2-submit'
)->
text
()
);
}
/**
* @param string $home
* @param string[] $attached
* @param string[] $methods
* @return string
*/
private
function
step3ActionForm
(
$home
,
$attached
,
$methods
)
{
$html
=
$this
->
msg
(
'centralauth-merge-step3-detail'
,
$this
->
getUser
()->
getName
()
)->
parseAsBlock
()
.
Html
::
rawElement
(
'h3'
,
[],
$this
->
msg
(
'centralauth-list-home-title'
)->
escaped
()
)
.
$this
->
msg
(
'centralauth-list-home-dryrun'
)->
parseAsBlock
()
.
$this
->
listAttached
(
[
$home
],
$methods
);
if
(
count
(
$attached
)
)
{
$html
.=
Html
::
rawElement
(
'h3'
,
[],
$this
->
msg
(
'centralauth-list-attached-title'
)->
escaped
()
)
.
$this
->
msg
(
'centralauth-list-attached-dryrun'
,
$this
->
getUser
()->
getName
(),
count
(
$attached
)
)->
parseAsBlock
();
}
$html
.=
$this
->
listAttached
(
$attached
,
$methods
)
.
Html
::
rawElement
(
'p'
,
[],
Html
::
submitButton
(
$this
->
msg
(
'centralauth-merge-step3-submit'
)->
text
(),
[
'name'
=>
'wpLogin'
]
)
);
return
$this
->
actionForm
(
'initial'
,
$this
->
msg
(
'centralauth-merge-step3-title'
)->
text
(),
$html
);
}
/**
* @return string
*/
private
function
attachActionForm
()
{
return
$this
->
passwordForm
(
'attach'
,
$this
->
msg
(
'centralauth-attach-title'
)->
text
(),
$this
->
msg
(
'centralauth-attach-text'
)->
escaped
(),
$this
->
msg
(
'centralauth-attach-submit'
)->
text
()
);
}
private
function
dryRunError
()
{
$this
->
getOutput
()->
addWikiMsg
(
'centralauth-disabled-dryrun'
);
}
/** @inheritDoc */
protected
function
getGroupName
()
{
return
'login'
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Aug 19 2026, 20:34 (7 w, 4 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
60/74/dbb57111c28d4152d6a1f0313259
Default Alt Text
SpecialMergeAccount.php (20 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment