PluginProbe
Migrate to WordPress.com / 6.65
Migrate to WordPress.com v6.65
6.72 6.65 trunk 5.72 5.81 5.88
wpcom-migration / recover.php

recover.php in Migrate to WordPress.com 6.65, at recover.php

176 lines 4.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) exit;
3 if (!class_exists('WPCOMRecover')) :
4 class WPCOMRecover {
5
6 const SECRET_TTL = 1800;
7 const TAG_LENGTH = 32;
8 const SALT_LENGTH = 64;
9 const MIN_SALT_LENGTH = 32;
10 const SALT_CONSTANT = 'AUTH_SALT';
11 const SALT_PLACEHOLDER = 'put your unique phrase here';
12
13 public static $default_secret_key = 'bv_default_secret_key';
14 private static $other_salt_constants = array(
15 'AUTH_KEY', 'SECURE_AUTH_KEY', 'SECURE_AUTH_SALT',
16 'LOGGED_IN_KEY', 'LOGGED_IN_SALT',
17 'NONCE_KEY', 'NONCE_SALT'
18 );
19
20 public static function saltMaterial($settings) {
21 $salt = self::configSalt();
22 if (!empty($salt)) {
23 return $salt;
24 }
25
26 return self::storedSalt($settings);
27 }
28
29 private static function configSalt() {
30 if (!defined(self::SALT_CONSTANT)) {
31 return null;
32 }
33
34 $value = constant(self::SALT_CONSTANT);
35 if (!is_string($value) || strlen($value) < self::MIN_SALT_LENGTH ||
36 self::isPlaceholder($value) || self::isSharedWithOtherSalts($value)) {
37 return null;
38 }
39
40 return $value;
41 }
42
43 private static function isSharedWithOtherSalts($value) {
44 foreach (self::$other_salt_constants as $constant) {
45 if (defined($constant) && constant($constant) === $value) {
46 return true;
47 }
48 }
49
50 return false;
51 }
52
53 private static function storedSalt($settings) {
54 $key_details = $settings->getOption(self::$default_secret_key);
55 if (!is_array($key_details) || !isset($key_details["salt"])) {
56 return null;
57 }
58
59 $salt = $key_details["salt"];
60 if (!is_string($salt) || strlen($salt) < self::MIN_SALT_LENGTH) {
61 return null;
62 }
63
64 return $salt;
65 }
66
67 private static function isPlaceholder($value) {
68 if ($value === self::SALT_PLACEHOLDER) {
69 return true;
70 }
71
72 #wp-config-sample.php is localized for some locales, so the placeholder
73 #is not always the English string. wp_salt() guards against the
74 #translated form the same way.
75 // phpcs:ignore WordPress.WP.I18n.MissingArgDomain
76 return function_exists('__') && $value === __('put your unique phrase here');
77 }
78
79 public static function defaultSecret($settings) {
80 $secret = self::getDefaultSecret($settings);
81 if (empty($secret)) {
82 $secret = WPCOMRecover::refreshDefaultSecret($settings);
83 }
84 return $secret;
85 }
86
87 public static function refreshDefaultSecret($settings) {
88 $settings->deleteOption(self::$default_secret_key);
89
90 $key_details = array();
91 $key_details["key"] = WPCOMAccount::randString(32);
92 $key_details["expires_at"] = time() + self::SECRET_TTL;
93
94 #Only carried when wp-config.php has nothing usable to bind the tag to.
95 if (empty(self::configSalt())) {
96 $key_details["salt"] = WPCOMAccount::randString(self::SALT_LENGTH);
97 }
98
99 $settings->updateOption(self::$default_secret_key, $key_details);
100
101 return $key_details["key"];
102 }
103
104 public static function connectionTag($settings) {
105 $secret = self::getDefaultSecret($settings);
106 if (empty($secret)) {
107 return null;
108 }
109
110 $material = self::saltMaterial($settings);
111 if (empty($material)) {
112 return null;
113 }
114
115 return substr(hash_hmac('sha256', $secret, $material), 0, self::TAG_LENGTH);
116 }
117
118 public static function verifyTag($settings, $tag) {
119 $expected = self::connectionTag($settings);
120 if (empty($expected)) {
121 return false;
122 }
123
124 return is_string($tag) && hash_equals($expected, $tag);
125 }
126
127 public static function deleteDefaultSecret($settings) {
128 return $settings->deleteOption(self::$default_secret_key);
129 }
130
131 public static function getDefaultSecret($settings) {
132 $key_details = $settings->getOption(self::$default_secret_key);
133
134 if (is_array($key_details) && $key_details["expires_at"] > time()) {
135 return $key_details["key"];
136 }
137
138 return null;
139 }
140
141 public static function getSecretStatus($settings) {
142 $key_details = $settings->getOption(self::$default_secret_key);
143 $status = 'ACTIVE';
144 if (!is_array($key_details)) {
145 $status = 'DELETED';
146 } elseif ($key_details["expires_at"] <= time()) {
147 $status = 'EXPIRED';
148 }
149
150 return $status;
151 }
152
153 public static function validate($key) {
154 return $key && strlen($key) >= 32;
155 }
156
157 public static function find($settings, $pubkey, $tag = null) {
158 if (!self::validate($pubkey)) {
159 return null;
160 }
161
162 if (!self::verifyTag($settings, $tag)) {
163 return null;
164 }
165
166 $secret = self::getDefaultSecret($settings);
167 if (!self::validate($secret)) {
168 return null;
169 }
170
171 $account = new WPCOMAccount($settings, $pubkey, $secret);
172 return $account;
173 }
174 }
175 endif;
176