The previous commit added five direct clients (Douyin, Microsoft, Facebook, Twitter, Apple) written against each platform's own endpoints. Maintaining five bespoke OAuth implementations — including Apple's ES256 client secret and Twitter's PKCE — is maintenance the bundled yurunsoft SDK does not ask for, and none of them could be verified without production credentials. Only providers yurunsoft/yurun-oauth-login actually implements stay on the direct surface: GitHub, Gitee, QQ, Google, Weibo, Weixin, Baidu and Alipay. Baidu and Alipay move into OAuthProviderBroker's existing client() switch and normalize() map rather than living in a separate class, so there is no new layer to reason about. OAuthProviderClient, its harness and its contract test are deleted outright (-809 lines). The Apple form_post handling added to handle_callback() is reverted too — without Apple there is no POST callback to read. The aggregate-login channel keeps its 16 platforms, matching the reference; that list describes what the aggregation provider offers, not a local implementation. Brand icons for those names stay for the same reason. Verification: 869 widget/navigation tests pass, the PSR-4 audit reports 0 errors, and the catalog constant, PHP schema and Vue schema now list the same 16 aggregate platforms.
226 lines
6.9 KiB
PHP
226 lines
6.9 KiB
PHP
<?php
|
|
/**
|
|
* @package Jio
|
|
*/
|
|
|
|
namespace Jio\Auth;
|
|
|
|
use Jio\Settings\Settings;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
final class OAuthProviderCatalog {
|
|
|
|
private const DIRECT = [
|
|
'github' => [
|
|
'label' => 'GitHub',
|
|
'id_key' => 'github_appid',
|
|
'secret_key' => 'github_appkey',
|
|
],
|
|
'gitee' => [
|
|
'label' => 'Gitee',
|
|
'id_key' => 'gitee_appid',
|
|
'secret_key' => 'gitee_appkey',
|
|
],
|
|
'qq' => [
|
|
'label' => 'QQ',
|
|
'id_key' => 'qq_appid',
|
|
'secret_key' => 'qq_appkey',
|
|
],
|
|
'google' => [
|
|
'label' => 'Google',
|
|
'id_key' => 'google_client_id',
|
|
'secret_key' => 'google_client_secret',
|
|
],
|
|
'weibo' => [
|
|
'label' => 'Weibo',
|
|
'id_key' => 'weibo_appid',
|
|
'secret_key' => 'weibo_appkey',
|
|
],
|
|
'weixin' => [
|
|
'label' => 'WeChat',
|
|
'id_key' => 'weixin_appid',
|
|
'secret_key' => 'weixin_appsecret',
|
|
],
|
|
'baidu' => [
|
|
'label' => '百度',
|
|
'id_key' => 'baidu_appid',
|
|
'secret_key' => 'baidu_appkey',
|
|
],
|
|
'alipay' => [
|
|
'label' => '支付宝',
|
|
'id_key' => 'alipay_appid',
|
|
'secret_key' => 'alipay_appkey',
|
|
'extra_keys' => ['private_key' => 'alipay_private_key'],
|
|
],
|
|
];
|
|
|
|
/** 彩虹聚合登录支持的平台,与参考主题一致。 */
|
|
public const CLOGIN_TYPES = [
|
|
'qq', 'weixin', 'alipay', 'weibo', 'douyin', 'baidu', 'github', 'gitee',
|
|
'dingtalk', 'huawei', 'xiaomi', 'google', 'microsoft', 'facebook', 'twitter', 'apple',
|
|
];
|
|
|
|
public static function direct_keys(): array {
|
|
return array_keys(self::DIRECT);
|
|
}
|
|
|
|
public static function all_binding_keys(): array {
|
|
$keys = array_merge(self::direct_keys(), ['weixingzh']);
|
|
foreach (self::CLOGIN_TYPES as $type) {
|
|
$keys[] = 'clogin_' . $type;
|
|
}
|
|
return $keys;
|
|
}
|
|
|
|
public static function is_direct(string $provider): bool {
|
|
return isset(self::DIRECT[sanitize_key($provider)]);
|
|
}
|
|
|
|
public static function is_binding_provider(string $provider): bool {
|
|
return in_array(sanitize_key($provider), self::all_binding_keys(), true);
|
|
}
|
|
|
|
public static function label(string $provider): string {
|
|
$provider = sanitize_key($provider);
|
|
if (isset(self::DIRECT[$provider])) {
|
|
return self::DIRECT[$provider]['label'];
|
|
}
|
|
if ($provider === 'weixingzh') {
|
|
return __('微信公众号', 'jio');
|
|
}
|
|
if (str_starts_with($provider, 'clogin_')) {
|
|
$type = substr($provider, 7);
|
|
if (in_array($type, self::CLOGIN_TYPES, true)) {
|
|
return self::label($type) . ' · ' . __('聚合', 'jio');
|
|
}
|
|
}
|
|
return ucfirst($provider);
|
|
}
|
|
|
|
public static function icon_key(string $provider): string {
|
|
$provider = sanitize_key($provider);
|
|
return str_starts_with($provider, 'clogin_') ? substr($provider, 7) : $provider;
|
|
}
|
|
|
|
public static function master_enabled(): bool {
|
|
return !Settings::close_sign() && (bool) Settings::get_value('oauth_s', false);
|
|
}
|
|
|
|
public static function provider_config(string $provider): ?array {
|
|
$provider = sanitize_key($provider);
|
|
if (!isset(self::DIRECT[$provider])) {
|
|
return null;
|
|
}
|
|
$settings = Settings::get_all();
|
|
$definition = self::DIRECT[$provider];
|
|
$client_id = trim((string) ($settings[$definition['id_key']] ?? ''));
|
|
$client_secret = trim((string) ($settings[$definition['secret_key']] ?? ''));
|
|
$extra = [];
|
|
foreach ((array) ($definition['extra_keys'] ?? []) as $field => $setting_key) {
|
|
$extra[$field] = trim((string) ($settings[$setting_key] ?? ''));
|
|
}
|
|
return [
|
|
'provider' => $provider,
|
|
'enabled' => self::master_enabled() && !empty($settings['oauth_' . $provider . '_s']),
|
|
'client_id' => $client_id,
|
|
'client_secret' => $client_secret,
|
|
'configured' => $client_id !== '' && $client_secret !== '',
|
|
] + $extra;
|
|
}
|
|
|
|
public static function enabled_direct_keys(): array {
|
|
if (!self::master_enabled()) {
|
|
return [];
|
|
}
|
|
$result = [];
|
|
foreach (self::direct_keys() as $provider) {
|
|
$config = self::provider_config($provider);
|
|
if ($config && $config['enabled'] && $config['configured']) {
|
|
$result[] = $provider;
|
|
}
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
public static function proxy_mode(): string {
|
|
$mode = sanitize_key((string) Settings::get_value('oauth_proxy_mode', 'close'));
|
|
return in_array($mode, ['close', 'server', 'client'], true) ? $mode : 'close';
|
|
}
|
|
|
|
public static function proxy_secret(): string {
|
|
return trim((string) Settings::get_value('oauth_proxy_secret', ''));
|
|
}
|
|
|
|
public static function proxy_server_url(): string {
|
|
return esc_url_raw(trim((string) Settings::get_value('oauth_proxy_server_url', '')));
|
|
}
|
|
|
|
public static function proxy_server_providers(): array {
|
|
$providers = (array) Settings::get_value('oauth_proxy_server_providers', []);
|
|
$result = [];
|
|
foreach (array_values(array_intersect(array_map('sanitize_key', $providers), self::direct_keys())) as $provider) {
|
|
$config = self::provider_config($provider);
|
|
if ($config && $config['configured']) {
|
|
$result[] = $provider;
|
|
}
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
public static function proxy_client_providers(): array {
|
|
$providers = (array) Settings::get_value('oauth_proxy_client_providers', []);
|
|
return array_values(array_intersect(array_map('sanitize_key', $providers), self::direct_keys()));
|
|
}
|
|
|
|
public static function bind_type(): string {
|
|
$type = sanitize_key((string) Settings::get_value('oauth_bind_type', 'auto'));
|
|
return in_array($type, ['auto', 'manual'], true) ? $type : 'auto';
|
|
}
|
|
|
|
public static function clogin_settings(): array {
|
|
$settings = Settings::get_all();
|
|
$raw = (array) ($settings['clogin_oauth_s'] ?? self::CLOGIN_TYPES);
|
|
$types = array_values(array_intersect(array_map('sanitize_key', $raw), self::CLOGIN_TYPES));
|
|
return [
|
|
'enabled' => self::master_enabled() && !empty($settings['clogin_s']),
|
|
'url' => esc_url_raw(trim((string) ($settings['clogin_url'] ?? ''))),
|
|
'id' => trim((string) ($settings['clogin_id'] ?? '')),
|
|
'key' => trim((string) ($settings['clogin_key'] ?? '')),
|
|
'types' => $types,
|
|
];
|
|
}
|
|
|
|
public static function enabled_login_keys(): array {
|
|
if (!self::master_enabled()) {
|
|
return [];
|
|
}
|
|
if (self::proxy_mode() === 'client') {
|
|
if (self::proxy_server_url() === '' || self::proxy_secret() === '') {
|
|
return [];
|
|
}
|
|
return self::proxy_client_providers();
|
|
}
|
|
$result = self::enabled_direct_keys();
|
|
$settings = Settings::get_all();
|
|
if (!empty($settings['oauth_weixingzh_s'])) {
|
|
$gzh_type = sanitize_key((string) ($settings['weixingzh_gzh_type'] ?? 'service'));
|
|
$has_base = trim((string) ($settings['weixingzh_token'] ?? '')) !== ''
|
|
&& trim((string) ($settings['weixingzh_appid'] ?? '')) !== '';
|
|
$has_mode = $gzh_type === 'subscribe'
|
|
? trim((string) ($settings['weixingzh_code_qrcode'] ?? '')) !== ''
|
|
: trim((string) ($settings['weixingzh_appsecret'] ?? '')) !== '';
|
|
if ($has_base && $has_mode) {
|
|
$result[] = 'weixingzh';
|
|
}
|
|
}
|
|
$clogin = self::clogin_settings();
|
|
if ($clogin['enabled'] && $clogin['url'] !== '' && $clogin['id'] !== '' && $clogin['key'] !== '') {
|
|
foreach ($clogin['types'] as $type) {
|
|
$result[] = 'clogin_' . $type;
|
|
}
|
|
}
|
|
return array_values(array_unique($result));
|
|
}
|
|
}
|