'github'], 60, true); check(\AKSRT\Auth\OAuthTransactionStore::peek($token, 'direct', true) !== null, 'transaction peek failed'); check(\AKSRT\Auth\OAuthTransactionStore::peek($token, 'other', true) === null, 'transaction kind mismatch accepted'); $_COOKIE['aksrt_oauth_browser'] = str_repeat('B', 43); check(\AKSRT\Auth\OAuthTransactionStore::claim($token, 'direct', true) === null, 'wrong browser claimed transaction'); $_COOKIE['aksrt_oauth_browser'] = str_repeat('A', 43); check(\AKSRT\Auth\OAuthTransactionStore::claim($token, 'direct', true) !== null, 'valid browser failed claim'); check(\AKSRT\Auth\OAuthTransactionStore::claim($token, 'direct', true) === null, 'transaction replay accepted'); $bindPass = \AKSRT\Auth\OAuthTransactionStore::issue('oauth_bind_pass', ['user_id' => 17, 'provider' => 'github'], 300, true); check(\AKSRT\Auth\OAuth::validate_bind_pass($bindPass, 'github', 17, false), 'valid bind pass peek failed'); check(!\AKSRT\Auth\OAuth::validate_bind_pass($bindPass, 'gitee', 17, true), 'wrong bind provider consumed as valid'); check(!\AKSRT\Auth\OAuth::validate_bind_pass($bindPass, 'github', 18, true), 'wrong bind user consumed as valid'); check(\AKSRT\Auth\OAuth::validate_bind_pass($bindPass, 'github', 17, true), 'valid bind pass claim failed after rejected mismatches'); check(!\AKSRT\Auth\OAuth::validate_bind_pass($bindPass, 'github', 17, true), 'bind pass replay accepted'); $GLOBALS['captcha_enabled'] = false; check(\AKSRT\Auth\OAuth::validate_bind_pass('', 'github', 17, true), 'disabled bind captcha required a pass'); $GLOBALS['captcha_enabled'] = true; $expired = \AKSRT\Auth\OAuthTransactionStore::issue('direct', [], 30, true); foreach ($GLOBALS['wp_options'] as $key => $row) { if (is_array($row) && ($row['kind'] ?? '') === 'direct') $GLOBALS['wp_options'][$key]['expires_at'] = time() - 1; } check(\AKSRT\Auth\OAuthTransactionStore::peek($expired, 'direct', true) === null, 'expired transaction accepted'); $request = [ 'v' => '2', 'request_id' => str_repeat('C', 43), 'provider' => 'github', 'action' => 'login', 'agent_back_url' => 'https://example.com/oauth/proxy/callback/', 'ts' => (string) time(), ]; $secret = 'test-secret-value'; $requestSign = \AKSRT\Auth\OAuthProxyProtocol::sign_request($request, $secret); check(\AKSRT\Auth\OAuthProxyProtocol::verify_request($request, $secret, $requestSign), 'request signature failed'); check(!\AKSRT\Auth\OAuthProxyProtocol::verify_callback($request, $secret, $requestSign), 'direction-separated HMAC failed'); $tampered = $request; $tampered['provider'] = 'qq'; check(!\AKSRT\Auth\OAuthProxyProtocol::verify_request($tampered, $secret, $requestSign), 'tampered request accepted'); check(!\AKSRT\Auth\OAuthProxyProtocol::timestamp_valid((string) (time() - 1000)), 'expired timestamp accepted'); check(\AKSRT\Auth\OAuthUrlPolicy::public_https('http://example.com') === '', 'HTTP URL accepted'); check(\AKSRT\Auth\OAuthUrlPolicy::public_https('https://user@example.com') === '', 'userinfo URL accepted'); check(\AKSRT\Auth\OAuthUrlPolicy::public_https('https://127.0.0.1') === '', 'loopback URL accepted'); check(\AKSRT\Auth\OAuthUrlPolicy::public_https('https://10.0.0.1') === '', 'private URL accepted'); check(\AKSRT\Auth\OAuthProxyProtocol::callback_url('https://example.com/wrong') === '', 'wrong callback path accepted'); $provider = \AKSRT\Admin\SchemaProvider::get_instance(); $base = $provider->get_defaults('users', 'oauth'); $base['oauth_s'] = true; $base['oauth_weixingzh_s'] = true; $base['weixingzh_gzh_type'] = 'service'; $base['weixingzh_appid'] = 'appid'; $base['weixingzh_appsecret'] = 'secret'; $base['weixingzh_token'] = '***'; $GLOBALS['wp_options']['aksrt_settings'] = []; check(!$provider->validate('users', $base, 'oauth')['valid'], 'masked missing token treated as configured'); $GLOBALS['wp_options']['aksrt_settings'] = ['weixingzh_token' => 'stored-token']; check($provider->validate('users', $base, 'oauth')['valid'], 'stored token not preserved by mask validation'); $provider->write_settings('users', ['weixingzh_token' => '***'], 'oauth'); check($GLOBALS['wp_options']['aksrt_settings']['weixingzh_token'] === 'stored-token', 'masked token overwrote stored secret'); $provider->write_settings('users', ['weixingzh_token' => 'replacement'], 'oauth'); check($GLOBALS['wp_options']['aksrt_settings']['weixingzh_token'] === 'replacement', 'new token failed to replace secret'); $provider->write_settings('users', ['__clear_secrets' => ['weixingzh_token']], 'oauth'); check(!isset($GLOBALS['wp_options']['aksrt_settings']['weixingzh_token']), 'explicit secret clear failed'); $GLOBALS['wp_options']['aksrt_settings']['weixingzh_token'] = 'final-token'; $clearData = $base; $clearData['weixingzh_token'] = '***'; $clearData['__clear_secrets'] = ['weixingzh_token']; check(!$provider->validate('users', $clearData, 'oauth')['valid'], 'active provider allowed required secret clear'); check($provider->read_settings('users', 'oauth')['weixingzh_token'] === '***', 'secret read was not masked'); echo "OAuth security harness passed.\n"; }