/wechat/status 与 /wechat/settings 自引入起只注册了路由、从未实现回调方法,后台「微信模板消息」页调用即 500。 按既定设计补齐:状态读取委托 WeChatNotify::get_status()(其既定用途即 REST 与 AJAX 复用),写入委托 Settings::update_wechat_settings() 并由 Integration 收敛键白名单;前端空密钥下发掩码 *** 时保留已存密钥,避免把密钥写成字面量。 新增 PHP harness 驱动真实 UserController + Integration + WeChatNotify 验证状态形状、掩码保留、缺省沿用、未知键丢弃与输入消毒。
152 lines
6.2 KiB
PHP
152 lines
6.2 KiB
PHP
<?php
|
|
/**
|
|
* WeChat template-message settings harness.
|
|
*
|
|
* Drives the REAL UserController REST callbacks (get_wechat_status /
|
|
* update_wechat_settings) against WP stubs so the previously-broken routes are
|
|
* covered end to end:
|
|
* - GET /wechat/status returns the WeChatNotify status shape (masked secret);
|
|
* - POST /wechat/settings persists through Integration's key whitelist;
|
|
* - the *** mask keeps the stored secret instead of overwriting it;
|
|
* - omitted fields fall back to current values; unknown keys are dropped;
|
|
* - inputs are sanitized before storage.
|
|
*
|
|
* Usage: php wechat-settings-harness.php -> prints "WeChat settings harness passed".
|
|
*/
|
|
|
|
namespace {
|
|
define('ABSPATH', __DIR__ . '/');
|
|
|
|
final class WP_REST_Response {
|
|
public $data;
|
|
public $status;
|
|
public function __construct($data = null, int $status = 200) {
|
|
$this->data = $data;
|
|
$this->status = $status;
|
|
}
|
|
}
|
|
|
|
final class WP_REST_Request {
|
|
private array $json;
|
|
public function __construct(array $json = []) { $this->json = $json; }
|
|
public function get_json_params(): array { return $this->json; }
|
|
public function get_method(): string { return 'POST'; }
|
|
}
|
|
|
|
// ---------- WP function stubs ----------
|
|
function __($s, $d = null) { return (string) $s; }
|
|
function sanitize_text_field($s) { return trim(strip_tags((string) $s)); }
|
|
function current_user_can($c) { return true; }
|
|
function wp_send_json_success($d) { echo (string) json_encode($d); }
|
|
function get_transient($k) { return $GLOBALS['wechat_transient'] ?? false; }
|
|
function get_option($k, $default = false) { return $GLOBALS['wechat_options'][$k] ?? $default; }
|
|
function update_option($k, $v) { $GLOBALS['wechat_options'][$k] = $v; return true; }
|
|
|
|
$GLOBALS['wechat_options'] = ['aksrt_wechat_settings' => [
|
|
'enabled' => true,
|
|
'app_id' => 'wxAPPID',
|
|
'app_secret' => 'SECRET123',
|
|
'template_id' => 'TPL1',
|
|
]];
|
|
$GLOBALS['wechat_transient'] = 'ACCESS_TOKEN';
|
|
|
|
$GLOBALS['wpdb'] = new class {
|
|
public $usermeta = 'wp_usermeta';
|
|
public function get_var($sql) { return 7; }
|
|
};
|
|
}
|
|
|
|
namespace AKSRT\Settings {
|
|
// Settings 层仅为薄委托,harness 直接对接真实 Integration。
|
|
class Settings {
|
|
public static function get_wechat_settings(): array { return Integration::get_wechat_settings(); }
|
|
public static function update_wechat_settings(array $settings): void { Integration::update_wechat_settings($settings); }
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
require_once dirname(__DIR__, 2) . '/src/Admin/ControllerBase.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Admin/UserControllerReportOperations.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Admin/UserControllerAuthPhoneOperations.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Admin/UserControllerRestrictionOperations.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Admin/UserControllerFollowOperations.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Admin/UserControllerProfileMediaOperations.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Admin/UserController.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Settings/Integration.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Settings/DomainGroups.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Payment/WeChatNotify.php';
|
|
|
|
$failures = [];
|
|
$check = static function (string $label, bool $ok) use (&$failures): void {
|
|
if (!$ok) {
|
|
$failures[] = $label;
|
|
}
|
|
};
|
|
$stored = static function (): array {
|
|
$v = get_option('aksrt_wechat_settings', []);
|
|
return is_array($v) ? $v : [];
|
|
};
|
|
|
|
$controller = \AKSRT\Admin\UserController::get_instance();
|
|
|
|
// 1) GET /wechat/status 返回完整状态形状(密钥掩码)。
|
|
$response = $controller->get_wechat_status(new WP_REST_Request());
|
|
$data = is_array($response->data) ? ($response->data['data'] ?? []) : [];
|
|
$check('status 含 enabled', array_key_exists('enabled', $data) && !empty($data['enabled']));
|
|
$check('status 含 appid', ($data['appid'] ?? '') === 'wxAPPID');
|
|
$check('status configured', !empty($data['configured']));
|
|
$check('status has_token', !empty($data['has_token']));
|
|
$check('status has_template', !empty($data['has_template']));
|
|
$check('status bound_users', ($data['bound_users'] ?? 0) === 7);
|
|
$check('status 掩码 app_secret', ($data['app_secret'] ?? '') === '***');
|
|
$check('status allowed_types 非空', !empty($data['allowed_types']));
|
|
|
|
// 2) 完整更新写入全部字段。
|
|
$response = $controller->update_wechat_settings(new WP_REST_Request([
|
|
'enabled' => true,
|
|
'app_id' => 'wxNEW',
|
|
'app_secret' => 'NEWSECRET',
|
|
'template_id' => 'TPL2',
|
|
]));
|
|
$check('更新写入 app_id', ($stored()['app_id'] ?? '') === 'wxNEW');
|
|
$check('更新写入 app_secret', ($stored()['app_secret'] ?? '') === 'NEWSECRET');
|
|
$check('更新写入 template_id', ($stored()['template_id'] ?? '') === 'TPL2');
|
|
$check('更新返回成功消息', str_contains((string) ($response->data['message'] ?? ''), '已保存'));
|
|
|
|
// 3) 掩码 *** 保留已存密钥。
|
|
$controller->update_wechat_settings(new WP_REST_Request([
|
|
'enabled' => true,
|
|
'app_id' => 'wxNEW',
|
|
'app_secret' => '***',
|
|
]));
|
|
$check('掩码保留原密钥', ($stored()['app_secret'] ?? '') === 'NEWSECRET');
|
|
|
|
// 4) 缺省字段沿用当前值,开关可关闭。
|
|
$controller->update_wechat_settings(new WP_REST_Request(['enabled' => false]));
|
|
$check('缺省字段沿用当前值', ($stored()['app_id'] ?? '') === 'wxNEW' && ($stored()['template_id'] ?? '') === 'TPL2');
|
|
$check('enabled 可关闭', empty($stored()['enabled']));
|
|
|
|
// 5) 输入消毒 + 未知键被白名单丢弃。
|
|
$controller->update_wechat_settings(new WP_REST_Request([
|
|
'app_id' => '<b>wxXSS</b>',
|
|
'evil' => 'x',
|
|
]));
|
|
$check('app_id 经消毒', ($stored()['app_id'] ?? '') === 'wxXSS');
|
|
$check('未知键被忽略', !array_key_exists('evil', $stored()));
|
|
|
|
// 6) 未配置时空密钥可显式清空。
|
|
update_option('aksrt_wechat_settings', ['enabled' => true, 'app_id' => 'a', 'app_secret' => '', 'template_id' => '']);
|
|
$controller->update_wechat_settings(new WP_REST_Request(['app_secret' => '']));
|
|
$check('空密钥可清存', ($stored()['app_secret'] ?? '') === '');
|
|
|
|
if ($failures) {
|
|
echo "WeChat settings harness FAILED\n";
|
|
foreach ($failures as $failure) {
|
|
echo ' - ' . $failure . "\n";
|
|
}
|
|
exit(1);
|
|
}
|
|
|
|
echo "WeChat settings harness passed\n";
|
|
}
|