Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 35 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
PostgresUtils | |
0.00% |
0 / 35 |
|
0.00% |
0 / 6 |
306 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
canCreateAccounts | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
12 | |||
isSuperUser | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
canCreateObjectsForWebUser | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
12 | |||
getInstallUserPermissions | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
isRoleMember | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
42 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Installer\Task; |
4 | |
5 | use MediaWiki\MainConfigNames; |
6 | use Wikimedia\Rdbms\IMaintainableDatabase; |
7 | |
8 | /** |
9 | * @internal For use by the installer |
10 | */ |
11 | class PostgresUtils { |
12 | private const MAX_ROLE_SEARCH_DEPTH = 5; |
13 | |
14 | /** @var ITaskContext */ |
15 | private $context; |
16 | |
17 | public function __construct( ITaskContext $context ) { |
18 | $this->context = $context; |
19 | } |
20 | |
21 | public function canCreateAccounts() { |
22 | $perms = $this->getInstallUserPermissions(); |
23 | return ( $perms && $perms->rolsuper ) || $perms->rolcreaterole; |
24 | } |
25 | |
26 | public function isSuperUser() { |
27 | $perms = $this->getInstallUserPermissions(); |
28 | return $perms && $perms->rolsuper; |
29 | } |
30 | |
31 | /** |
32 | * Returns true if the install user is able to create objects owned |
33 | * by the web user, false otherwise. |
34 | * @return bool |
35 | */ |
36 | public function canCreateObjectsForWebUser() { |
37 | if ( $this->isSuperUser() ) { |
38 | return true; |
39 | } |
40 | |
41 | $status = $this->context->getConnection( ITaskContext::CONN_CREATE_DATABASE ); |
42 | if ( !$status->isOK() ) { |
43 | return false; |
44 | } |
45 | $conn = $status->getDB(); |
46 | $installerId = $conn->selectField( '"pg_catalog"."pg_roles"', 'oid', |
47 | [ 'rolname' => $this->context->getOption( 'InstallUser' ) ], __METHOD__ ); |
48 | $webId = $conn->selectField( '"pg_catalog"."pg_roles"', 'oid', |
49 | [ 'rolname' => $this->context->getConfigVar( MainConfigNames::DBuser ) ], __METHOD__ ); |
50 | |
51 | return self::isRoleMember( $conn, $installerId, $webId, self::MAX_ROLE_SEARCH_DEPTH ); |
52 | } |
53 | |
54 | private function getInstallUserPermissions() { |
55 | $status = $this->context->getConnection( ITaskContext::CONN_CREATE_DATABASE ); |
56 | if ( !$status->isOK() ) { |
57 | return false; |
58 | } |
59 | $conn = $status->getDB(); |
60 | $superuser = $this->context->getOption( 'InstallUser' ); |
61 | |
62 | $row = $conn->selectRow( '"pg_catalog"."pg_roles"', '*', |
63 | [ 'rolname' => $superuser ], __METHOD__ ); |
64 | |
65 | return $row; |
66 | } |
67 | |
68 | /** |
69 | * Recursive helper for canCreateObjectsForWebUser(). |
70 | * @param IMaintainableDatabase $conn |
71 | * @param int $targetMember Role ID of the member to look for |
72 | * @param int $group Role ID of the group to look for |
73 | * @param int $maxDepth Maximum recursive search depth |
74 | * @return bool |
75 | */ |
76 | private function isRoleMember( $conn, $targetMember, $group, $maxDepth ) { |
77 | if ( $targetMember === $group ) { |
78 | // A role is always a member of itself |
79 | return true; |
80 | } |
81 | // Get all members of the given group |
82 | $res = $conn->select( '"pg_catalog"."pg_auth_members"', [ 'member' ], |
83 | [ 'roleid' => $group ], __METHOD__ ); |
84 | foreach ( $res as $row ) { |
85 | if ( $row->member == $targetMember ) { |
86 | // Found target member |
87 | return true; |
88 | } |
89 | // Recursively search each member of the group to see if the target |
90 | // is a member of it, up to the given maximum depth. |
91 | if ( $maxDepth > 0 && |
92 | $this->isRoleMember( $conn, $targetMember, $row->member, $maxDepth - 1 ) |
93 | ) { |
94 | // Found member of member |
95 | return true; |
96 | } |
97 | } |
98 | |
99 | return false; |
100 | } |
101 | } |