包含:登录失败锁定、90天密码有效期、30分钟会话超时、 强制改密、登录审计日志、屏幕水印、企业背景图、 备案信息固定底部、favicon、JS空集合保护、 会话过期体验优化(403 JSON)、display_errors 关闭、 固定 key 根治 Integrity check failed 等全部改动 注意:config.inc.php/.htaccess/.user.ini 含敏感信息, 通过 .gitignore 排除,勿推送到公开仓库。
229 lines
5.8 KiB
PHP
229 lines
5.8 KiB
PHP
<?php
|
|
namespace MRBS\Auth;
|
|
|
|
use MRBS\User;
|
|
|
|
/**
|
|
* A class for authenticating against a Wix system. It requires code to be installed in
|
|
* http-functions.js in the Wix backend. See wix/README for full details.
|
|
*
|
|
* It would be nice to be able to use Wix's OAuth2 server, but it seems to be limited to Wix apps.
|
|
*
|
|
* Another approach might be to use the Wix backend function getMember(), but this doesn't work inside
|
|
* http_functions as the URL endpoint for http_functions is not associated with a user session.
|
|
*/
|
|
class AuthWix extends Auth
|
|
{
|
|
public function validateUser(
|
|
#[\SensitiveParameter]
|
|
?string $user,
|
|
#[\SensitiveParameter]
|
|
?string $pass)
|
|
{
|
|
if (!isset($user) || !isset($pass))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
$params = array(
|
|
'email' => $user,
|
|
'password' => $pass
|
|
);
|
|
|
|
$result = $this->http_functions('validateMember', $params);
|
|
|
|
if ($result === false)
|
|
{
|
|
// curl_exec failure: we'll return false anyway
|
|
return $result;
|
|
}
|
|
|
|
return (json_decode($result)) ? $user : false;
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public function canValidateByEmail() : bool
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public function canValidateByUsername() : bool
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
protected function getUserFresh(string $username) : ?User
|
|
{
|
|
global $auth;
|
|
|
|
$params = array('email' => $username);
|
|
$result = $this->http_functions('getMemberByEmail', $params);
|
|
|
|
// The username doesn't exist - return NULL
|
|
if (($result === false) || ($result === '') || ($result === json_encode(null)))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
$result = json_decode($result);
|
|
|
|
$user = new User($username);
|
|
|
|
// Set the email address
|
|
$user->email = $result->member->loginEmail;
|
|
|
|
// Set the display name
|
|
$property = $auth['wix']['display_name_property'] ?? 'name';
|
|
if (isset($result->member->$property) && ($result->member->$property !== ''))
|
|
{
|
|
$user->display_name = $result->member->$property;
|
|
}
|
|
else
|
|
{
|
|
$user->display_name = $result->member->loginEmail;
|
|
}
|
|
|
|
// Set the level
|
|
// First get the default level. Any admins defined in the config
|
|
// file override settings in the external database.
|
|
$user->level = $this->getDefaultLevel($username);
|
|
|
|
// Then if they are not an admin get their admin status from Wix
|
|
if (($user->level < 2) && isset($result->badges) && in_array($auth['wix']['admin_badge'], $result->badges))
|
|
{
|
|
$user->level = 2;
|
|
}
|
|
|
|
return $user;
|
|
}
|
|
|
|
|
|
// Return an array of users, indexed by 'username' and 'display_name'
|
|
public function getUsernames() : array
|
|
{
|
|
global $auth;
|
|
|
|
$params = array();
|
|
|
|
if (isset($auth['wix']['display_name_property']))
|
|
{
|
|
$params['display_name_property'] = $auth['wix']['display_name_property'];
|
|
}
|
|
|
|
$result = $this->http_functions('getMemberNames', $params);
|
|
|
|
if ($result === false)
|
|
{
|
|
return array();
|
|
}
|
|
|
|
$users = json_decode($result, true);
|
|
|
|
self::sortUsers($users);
|
|
|
|
return $users;
|
|
}
|
|
|
|
|
|
private function http_functions(string $function, array $params)
|
|
{
|
|
global $auth, $server;
|
|
|
|
// Add a trailing '/' if necessary
|
|
if (!str_ends_with($auth['wix']['site_url'], '/'))
|
|
{
|
|
$auth['wix']['site_url'] .= '/';
|
|
}
|
|
|
|
// Get a user agent to keep the other end happy
|
|
if (isset($server['HTTP_USER_AGENT']) && ($server['HTTP_USER_AGENT'] !== ''))
|
|
{
|
|
$user_agent = $server['HTTP_USER_AGENT'];
|
|
}
|
|
else
|
|
{
|
|
$user_agent = 'PHP';
|
|
}
|
|
|
|
// Add in the API key
|
|
$params['key'] = $auth['wix']['mrbs_api_key'];
|
|
// And the API key secret name in Wix
|
|
$params['secret_name'] = $auth['wix']['mrbs_api_key_secret_name'];
|
|
|
|
// And the limit, for internal use by the Wix backend code
|
|
if (isset($auth['wix']['limit']))
|
|
{
|
|
$params['limit'] = $auth['wix']['limit'];
|
|
}
|
|
|
|
$url = $auth['wix']['site_url'] . "_functions/$function";
|
|
self::debug("URL=\"$url\"");
|
|
|
|
$ch = curl_init();
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
// Necessary to prevent "HTTP/2 stream 0 was not closed cleanly: INTERNAL_ERROR (err 2)" error;
|
|
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
|
// Necessary to prevent "OpenSSL SSL_read: Connection reset by peer, errno 104" error;
|
|
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
|
|
// Use compression if we can
|
|
if (defined('CURLOPT_ENCODING'))
|
|
{
|
|
curl_setopt($ch, CURLOPT_ENCODING, '');
|
|
}
|
|
// Get some debug info in case there's an error
|
|
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
|
$stream = fopen('php://temp', 'w+');
|
|
curl_setopt($ch, CURLOPT_STDERR, $stream);
|
|
|
|
$result = curl_exec($ch);
|
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
|
|
if ($result === false)
|
|
{
|
|
rewind($stream);
|
|
$message = curl_error($ch);
|
|
$message .= "\n\nCurl verbose log:\n\n" . stream_get_contents($stream);
|
|
trigger_error($message, E_USER_WARNING);
|
|
}
|
|
elseif ($http_code != 200)
|
|
{
|
|
trigger_error("Curl received HTTP response code $http_code: $result", E_USER_WARNING);
|
|
$result = false;
|
|
}
|
|
|
|
fclose($stream);
|
|
|
|
// curl_close() doesn't do anything from PHP 8.0 onwards (because the curl
|
|
// handle is an object and not a resource) and is deprecated from PHP 8.5.
|
|
assert(version_compare(MRBS_MIN_PHP_VERSION, '8.0.0', '<'), "The code below is now redundant.");
|
|
if (version_compare(PHP_VERSION, '8.0.0') < 0)
|
|
{
|
|
curl_close($ch);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
|
|
private static function debug(string $message) : void
|
|
{
|
|
global $auth;
|
|
|
|
if ($auth['wix']['debug'])
|
|
{
|
|
self::logDebugMessage($message);
|
|
}
|
|
}
|
|
|
|
}
|