PluginProbe
Pronamic Client / trunk
Pronamic Client vtrunk
2.4.1 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.4.0 1.5.0 1.6.0 1.6.1 1.7.0 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 All 54 releases
pronamic-client / classes / AdminerModule.php

AdminerModule.php in Pronamic Client trunk, at classes/AdminerModule.php

185 lines 4.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Pronamic\WordPress\PronamicClient;
4
5 use WP_Admin_Bar;
6
7 class AdminerModule {
8 /**
9 * Instance of this class.
10 *
11 * @var self
12 */
13 protected static $instance = null;
14
15 /**
16 * Plugin.
17 *
18 * @var Plugin
19 */
20 private $plugin;
21
22 /**
23 * Construct Adminer module.
24 *
25 * @param Plugin $plugin Plugin.
26 */
27 private function __construct( Plugin $plugin ) {
28 $this->plugin = $plugin;
29
30 \add_action( 'admin_post_pronamic_client_adminer_login', [ $this, 'adminer_login' ] );
31
32 \add_action( 'admin_bar_menu', [ $this, 'admin_bar_menu' ], 20, 1 );
33 }
34
35 /**
36 * Get the Adminer login URL.
37 *
38 * @return string
39 */
40 private function get_login_url() {
41 return \wp_nonce_url(
42 \add_query_arg(
43 [
44 'action' => 'pronamic_client_adminer_login',
45 ],
46 \admin_url( 'admin-post.php' )
47 ),
48 'pronamic_client_adminer_login'
49 );
50 }
51
52 /**
53 * Add Adminer to the Pronamic admin bar menu.
54 *
55 * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar instance.
56 */
57 public function admin_bar_menu( WP_Admin_Bar $wp_admin_bar ) {
58 if ( ! \current_user_can( 'pronamic_client' ) ) {
59 return;
60 }
61
62 $wp_admin_bar->add_menu(
63 [
64 'parent' => 'pronamic',
65 'id' => 'pronamic_adminer',
66 'title' => \__( 'Adminer', 'pronamic-client' ),
67 'href' => $this->get_login_url(),
68 'meta' => [
69 'target' => '_blank',
70 'rel' => 'noopener noreferrer',
71 ],
72 ]
73 );
74 }
75
76 /**
77 * Login to Adminer.
78 */
79 public function adminer_login() {
80 if ( ! \current_user_can( 'pronamic_client' ) ) {
81 \wp_die(
82 esc_html__( 'You are not allowed to access Adminer.', 'pronamic-client' ),
83 esc_html__( 'Forbidden', 'pronamic-client' ),
84 403
85 );
86 }
87
88 \check_admin_referer( 'pronamic_client_adminer_login' );
89
90 $adminer_url = 'https://www.adminer.org/latest.php';
91
92 $filename = 'pronamic-client-adminer-' . md5( gmdate( 'Y-m-d' ) ) . '.php';
93
94 $adminer_path = \sys_get_temp_dir() . \DIRECTORY_SEPARATOR . $filename;
95
96 if ( ! \is_file( $adminer_path ) ) {
97 $code = \file_get_contents( $adminer_url );
98
99 if ( false === $code ) {
100 \wp_die(
101 esc_html__( 'Adminer download failed.', 'pronamic-client' ),
102 esc_html__( 'Error', 'pronamic-client' ),
103 500
104 );
105 }
106
107 // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_file_put_contents
108 \file_put_contents( $adminer_path, $code );
109 }
110
111 $driver = 'server';
112 $server = DB_HOST;
113 $username = DB_USER;
114 $password = DB_PASSWORD;
115 $db = DB_NAME;
116
117 if ( \defined( 'DB_ENGINE' ) && 'sqlite' === \DB_ENGINE ) {
118 $driver = 'sqlite';
119 }
120
121 if ( \defined( 'FQDB' ) ) {
122 $db = \FQDB;
123 }
124
125 $token = $this->build_adminer_token(
126 [
127 'driver' => $driver,
128 'server' => $server,
129 'username' => $username,
130 'password' => $password,
131 'db' => $db,
132 ]
133 );
134
135 $adminer_url = \add_query_arg(
136 [ 'pronamic_client_adminer_token' => $token ],
137 \plugins_url( 'adminer/', $this->plugin->file )
138 );
139
140 \wp_safe_redirect( $adminer_url );
141
142 exit;
143 }
144
145 /**
146 * Build a single-use Adminer login token.
147 *
148 * The DB credentials are encrypted in a short-lived temp file. The token
149 * identifies the file and derives its encryption key.
150 *
151 * @param array<string, string> $credentials Driver, server, username, password, db.
152 * @return string
153 */
154 private function build_adminer_token( array $credentials ) {
155 $token = \md5( \random_bytes( 32 ) );
156 $creds_file = \sys_get_temp_dir() . \DIRECTORY_SEPARATOR . '.' . $token;
157 $key = \hash( 'sha256', $token, true );
158 $iv = \random_bytes( 16 );
159 $json = \wp_json_encode( $credentials );
160 $cipher = \openssl_encrypt( $json, 'aes-256-cbc', $key, \OPENSSL_RAW_DATA, $iv );
161
162 // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_file_put_contents
163 \file_put_contents( $creds_file, $iv . $cipher );
164
165 // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.chmod_chmod
166 \chmod( $creds_file, 0600 );
167
168 return $token;
169 }
170
171 /**
172 * Return an instance of this class.
173 *
174 * @param Plugin $plugin Plugin.
175 * @return self
176 */
177 public static function get_instance( Plugin $plugin ) {
178 if ( null === self::$instance ) {
179 self::$instance = new self( $plugin );
180 }
181
182 return self::$instance;
183 }
184 }
185