2022-09-13 13:14:49 +00:00
|
|
|
<?php
|
|
|
|
namespace Misuzu\SharpChat;
|
|
|
|
|
2023-07-22 15:02:41 +00:00
|
|
|
use RuntimeException;
|
2023-01-02 23:48:04 +00:00
|
|
|
use Index\Colour\Colour;
|
2023-01-06 20:22:03 +00:00
|
|
|
use Index\Routing\IRouter;
|
2023-07-18 22:24:23 +00:00
|
|
|
use Index\Http\HttpFx;
|
2023-07-12 21:52:55 +00:00
|
|
|
use Misuzu\AuthToken;
|
2023-07-28 20:06:12 +00:00
|
|
|
use Misuzu\Auth\Sessions;
|
2023-01-01 20:23:53 +00:00
|
|
|
use Misuzu\Config\IConfig;
|
2023-07-12 21:52:55 +00:00
|
|
|
use Misuzu\Emoticons\Emotes;
|
2023-07-26 18:19:46 +00:00
|
|
|
use Misuzu\Users\Bans;
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
// Replace
|
|
|
|
use Misuzu\Users\User;
|
|
|
|
|
|
|
|
final class SharpChatRoutes {
|
2023-01-01 20:23:53 +00:00
|
|
|
private IConfig $config;
|
2023-07-26 18:19:46 +00:00
|
|
|
private Bans $bans;
|
2023-07-12 21:52:55 +00:00
|
|
|
private Emotes $emotes;
|
2023-07-28 20:06:12 +00:00
|
|
|
private Sessions $sessions;
|
2023-07-18 22:33:13 +00:00
|
|
|
private string $hashKey;
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-07-28 20:06:12 +00:00
|
|
|
public function __construct(
|
|
|
|
IRouter $router,
|
|
|
|
IConfig $config,
|
|
|
|
Bans $bans,
|
|
|
|
Emotes $emotes,
|
|
|
|
Sessions $sessions
|
|
|
|
) {
|
2023-01-01 20:23:53 +00:00
|
|
|
$this->config = $config;
|
2023-07-26 18:19:46 +00:00
|
|
|
$this->bans = $bans;
|
2023-07-12 21:52:55 +00:00
|
|
|
$this->emotes = $emotes;
|
2023-07-28 20:06:12 +00:00
|
|
|
$this->sessions = $sessions;
|
2023-07-18 22:33:13 +00:00
|
|
|
$this->hashKey = $this->config->getString('hashKey', 'woomy');
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
// Simplify default error pages
|
2023-07-18 22:24:23 +00:00
|
|
|
if($router instanceof HttpFx)
|
|
|
|
$router->use('/_sockchat', function() use($router) {
|
|
|
|
$router->addErrorHandler(400, function($response) {
|
|
|
|
$response->setContent('HTTP 400');
|
|
|
|
});
|
|
|
|
$router->addErrorHandler(403, function($response) {
|
|
|
|
$response->setContent('HTTP 403');
|
|
|
|
});
|
|
|
|
$router->addErrorHandler(404, function($response) {
|
|
|
|
$response->setContent('HTTP 404');
|
|
|
|
});
|
|
|
|
$router->addErrorHandler(500, function($response) {
|
|
|
|
$response->setContent('HTTP 500');
|
|
|
|
});
|
|
|
|
$router->addErrorHandler(503, function($response) {
|
|
|
|
$response->setContent('HTTP 503');
|
|
|
|
});
|
2023-02-08 00:06:15 +00:00
|
|
|
});
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
// Public endpoints
|
2023-02-08 00:06:15 +00:00
|
|
|
$router->get('/_sockchat/emotes', [$this, 'getEmotes']);
|
|
|
|
$router->get('/_sockchat/login', [$this, 'getLogin']);
|
|
|
|
$router->options('/_sockchat/token', [$this, 'getToken']);
|
|
|
|
$router->get('/_sockchat/token', [$this, 'getToken']);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
// Private endpoints
|
2023-02-08 00:06:15 +00:00
|
|
|
$router->post('/_sockchat/bump', [$this, 'postBump']);
|
|
|
|
$router->post('/_sockchat/verify', [$this, 'postVerify']);
|
|
|
|
$router->get('/_sockchat/bans/list', [$this, 'getBanList']);
|
|
|
|
$router->get('/_sockchat/bans/check', [$this, 'getBanCheck']);
|
|
|
|
$router->post('/_sockchat/bans/create', [$this, 'postBanCreate']);
|
|
|
|
$router->delete('/_sockchat/bans/revoke', [$this, 'deleteBanRevoke']);
|
2022-09-13 13:14:49 +00:00
|
|
|
}
|
|
|
|
|
2023-07-12 21:52:55 +00:00
|
|
|
public function getEmotes($response, $request): array {
|
2022-09-13 13:14:49 +00:00
|
|
|
$response->setHeader('Access-Control-Allow-Origin', '*');
|
|
|
|
$response->setHeader('Access-Control-Allow-Methods', 'GET');
|
|
|
|
|
2023-07-12 21:52:55 +00:00
|
|
|
$emotes = $this->emotes->getAllEmotes(withStrings: true);
|
2022-09-13 13:14:49 +00:00
|
|
|
$out = [];
|
|
|
|
|
2023-07-12 21:52:55 +00:00
|
|
|
foreach($emotes as $emoteInfo) {
|
2022-09-13 13:14:49 +00:00
|
|
|
$strings = [];
|
|
|
|
|
2023-07-12 21:52:55 +00:00
|
|
|
foreach($emoteInfo->getStrings() as $stringInfo)
|
|
|
|
$strings[] = sprintf(':%s:', $stringInfo->getString());
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
$out[] = [
|
|
|
|
'Text' => $strings,
|
2023-07-12 21:52:55 +00:00
|
|
|
'Image' => $emoteInfo->getUrl(),
|
|
|
|
'Hierarchy' => $emoteInfo->getMinRank(),
|
2022-09-13 13:14:49 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $out;
|
|
|
|
}
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
public function getLogin($response, $request): void {
|
2022-09-13 13:14:49 +00:00
|
|
|
$currentUser = User::getCurrent();
|
2023-01-01 20:23:53 +00:00
|
|
|
$configKey = $request->hasParam('legacy') ? 'chatPath.legacy' : 'chatPath.normal';
|
2023-07-18 21:48:44 +00:00
|
|
|
$chatPath = $this->config->getString($configKey, '/');
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
$response->redirect(
|
|
|
|
$currentUser === null
|
|
|
|
? url('auth-login')
|
|
|
|
: $chatPath
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
public function getToken($response, $request) {
|
2022-09-13 13:14:49 +00:00
|
|
|
$host = $request->hasHeader('Host') ? $request->getHeaderFirstLine('Host') : '';
|
|
|
|
$origin = $request->hasHeader('Origin') ? $request->getHeaderFirstLine('Origin') : '';
|
|
|
|
$originHost = strtolower(parse_url($origin, PHP_URL_HOST) ?? '');
|
|
|
|
|
|
|
|
if(!empty($originHost) && $originHost !== $host) {
|
2023-07-18 21:48:44 +00:00
|
|
|
$whitelist = $this->config->getArray('origins', []);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
if(!in_array($originHost, $whitelist))
|
|
|
|
return 403;
|
|
|
|
|
|
|
|
$originProto = strtolower(parse_url($origin, PHP_URL_SCHEME));
|
|
|
|
$origin = $originProto . '://' . $originHost;
|
|
|
|
|
|
|
|
$response->setHeader('Access-Control-Allow-Origin', $origin);
|
|
|
|
$response->setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
|
|
|
|
$response->setHeader('Access-Control-Allow-Credentials', 'true');
|
|
|
|
$response->setHeader('Vary', 'Origin');
|
|
|
|
}
|
|
|
|
|
|
|
|
if($request->getMethod() === 'OPTIONS')
|
|
|
|
return 204;
|
|
|
|
|
2023-07-28 20:06:12 +00:00
|
|
|
if(!AuthToken::hasCurrent())
|
|
|
|
return ['ok' => false, 'err' => 'token'];
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-05-21 18:15:04 +00:00
|
|
|
$token = AuthToken::getCurrent();
|
|
|
|
|
2023-07-28 20:06:12 +00:00
|
|
|
try {
|
|
|
|
$sessionInfo = $this->sessions->getSession(sessionToken: $token->getSessionToken());
|
|
|
|
} catch(RuntimeException $ex) {
|
|
|
|
return ['ok' => false, 'err' => 'session'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if($sessionInfo->hasExpired())
|
|
|
|
return ['ok' => false, 'err' => 'expired'];
|
|
|
|
|
|
|
|
$userInfo = User::byId((int)$sessionInfo->getUserId());
|
|
|
|
$userId = $token->hasImpersonatedUserId() && $userInfo->isSuper()
|
2023-05-21 18:15:04 +00:00
|
|
|
? $token->getImpersonatedUserId()
|
2023-07-28 20:06:12 +00:00
|
|
|
: $userInfo->getId();
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
return [
|
|
|
|
'ok' => true,
|
2023-07-28 20:06:12 +00:00
|
|
|
'usr' => (int)$userId,
|
2022-09-13 13:14:49 +00:00
|
|
|
'tkn' => $token->pack(),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
public function postBump($response, $request) {
|
|
|
|
if(!$request->hasHeader('X-SharpChat-Signature'))
|
2022-09-13 13:14:49 +00:00
|
|
|
return 400;
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
if($request->isFormContent()) {
|
|
|
|
$content = $request->getContent();
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
$bumpList = $content->getParam('u', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
|
|
|
|
if(!is_array($bumpList))
|
|
|
|
return 400;
|
|
|
|
|
|
|
|
$userTime = (int)$content->getParam('t', FILTER_SANITIZE_NUMBER_INT);
|
|
|
|
$signature = "bump#{$userTime}";
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
foreach($bumpList as $userId => $ipAddr)
|
|
|
|
$signature .= "#{$userId}:{$ipAddr}";
|
2023-07-18 22:33:13 +00:00
|
|
|
} else return 400;
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
$userHash = (string)$request->getHeaderFirstLine('X-SharpChat-Signature');
|
|
|
|
$realHash = hash_hmac('sha256', $signature, $this->hashKey);
|
|
|
|
if(!hash_equals($realHash, $userHash))
|
|
|
|
return 403;
|
2023-07-18 22:33:13 +00:00
|
|
|
if($userTime < time() - 60)
|
|
|
|
return 403;
|
2023-02-08 00:06:15 +00:00
|
|
|
|
|
|
|
foreach($bumpList as $userId => $ipAddr)
|
|
|
|
User::byId($userId)->bumpActivity($ipAddr);
|
2022-09-13 13:14:49 +00:00
|
|
|
}
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
public function postVerify($response, $request) {
|
|
|
|
if(!$request->hasHeader('X-SharpChat-Signature'))
|
|
|
|
return 400;
|
|
|
|
|
2023-07-18 22:33:13 +00:00
|
|
|
if($request->isFormContent()) {
|
2023-02-08 00:06:15 +00:00
|
|
|
$content = $request->getContent();
|
|
|
|
$authMethod = (string)$content->getParam('method');
|
|
|
|
$authToken = (string)$content->getParam('token');
|
|
|
|
$ipAddress = (string)$content->getParam('ipaddr');
|
|
|
|
} else
|
2022-09-13 13:14:49 +00:00
|
|
|
return ['success' => false, 'reason' => 'request'];
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
$userHash = (string)$request->getHeaderFirstLine('X-SharpChat-Signature');
|
2022-09-13 13:14:49 +00:00
|
|
|
if(strlen($userHash) !== 64)
|
|
|
|
return ['success' => false, 'reason' => 'length'];
|
|
|
|
|
2023-07-18 22:24:23 +00:00
|
|
|
if(empty($authMethod) || empty($authToken) || empty($ipAddress))
|
2023-02-08 00:06:15 +00:00
|
|
|
return ['success' => false, 'reason' => 'data'];
|
|
|
|
|
2023-07-18 22:33:13 +00:00
|
|
|
$signature = "verify#{$authMethod}#{$authToken}#{$ipAddress}";
|
2023-02-08 00:06:15 +00:00
|
|
|
$realHash = hash_hmac('sha256', $signature, $this->hashKey);
|
|
|
|
if(!hash_equals($realHash, $userHash))
|
|
|
|
return ['success' => false, 'reason' => 'hash'];
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
if($authMethod === 'SESS' || $authMethod === 'Misuzu') {
|
|
|
|
$authTokenInfo = AuthToken::unpack($authToken);
|
|
|
|
if($authTokenInfo->isValid())
|
|
|
|
$authToken = $authTokenInfo->getSessionToken();
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
try {
|
2023-07-28 20:06:12 +00:00
|
|
|
$sessionInfo = $this->sessions->getSession(sessionToken: $authToken);
|
2023-07-22 15:02:41 +00:00
|
|
|
} catch(RuntimeException $ex) {
|
2022-09-13 13:14:49 +00:00
|
|
|
return ['success' => false, 'reason' => 'token'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if($sessionInfo->hasExpired()) {
|
2023-07-28 20:06:12 +00:00
|
|
|
$this->sessions->deleteSessions(sessionInfos: $sessionInfo);
|
2022-09-13 13:14:49 +00:00
|
|
|
return ['success' => false, 'reason' => 'expired'];
|
|
|
|
}
|
|
|
|
|
2023-07-28 20:06:12 +00:00
|
|
|
$this->sessions->updateSession(sessionInfo: $sessionInfo, remoteAddr: $ipAddress);
|
2023-02-08 00:06:15 +00:00
|
|
|
|
2023-07-28 20:06:12 +00:00
|
|
|
$userInfo = User::byId((int)$sessionInfo->getUserId());
|
2023-05-21 18:15:04 +00:00
|
|
|
if($authTokenInfo->hasImpersonatedUserId() && $userInfo->isSuper()) {
|
|
|
|
$userInfoReal = $userInfo;
|
|
|
|
|
|
|
|
try {
|
|
|
|
$userInfo = User::byId($authTokenInfo->getImpersonatedUserId());
|
2023-07-22 15:02:41 +00:00
|
|
|
} catch(RuntimeException $ex) {
|
2023-05-21 18:15:04 +00:00
|
|
|
$userInfo = $userInfoReal;
|
|
|
|
}
|
|
|
|
}
|
2022-09-13 13:14:49 +00:00
|
|
|
} else {
|
|
|
|
return ['success' => false, 'reason' => 'unsupported'];
|
|
|
|
}
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
if(empty($userInfo))
|
|
|
|
return ['success' => false, 'reason' => 'user'];
|
|
|
|
|
|
|
|
$userInfo->bumpActivity($ipAddress);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
return [
|
|
|
|
'success' => true,
|
|
|
|
'user_id' => $userInfo->getId(),
|
|
|
|
'username' => $userInfo->getUsername(),
|
2023-01-02 23:48:04 +00:00
|
|
|
'colour_raw' => Colour::toMisuzu($userInfo->getColour()),
|
2022-09-13 13:14:49 +00:00
|
|
|
'rank' => $rank = $userInfo->getRank(),
|
|
|
|
'hierarchy' => $rank,
|
|
|
|
'perms' => SharpChatPerms::convert($userInfo),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
public function getBanList($response, $request) {
|
|
|
|
if(!$request->hasHeader('X-SharpChat-Signature'))
|
|
|
|
return 400;
|
|
|
|
|
|
|
|
$userHash = (string)$request->getHeaderFirstLine('X-SharpChat-Signature');
|
|
|
|
$userTime = (int)$request->getParam('x', FILTER_SANITIZE_NUMBER_INT);
|
|
|
|
|
|
|
|
$realHash = hash_hmac('sha256', "list#{$userTime}", $this->hashKey);
|
|
|
|
if(!hash_equals($realHash, $userHash) || $userTime < time() - 60)
|
|
|
|
return 403;
|
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
$list = [];
|
|
|
|
$bans = $this->bans->getBans(activeOnly: true);
|
|
|
|
$userInfos = [];
|
2023-02-08 00:06:15 +00:00
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
foreach($bans as $banInfo) {
|
|
|
|
$userId = $banInfo->getUserId();
|
|
|
|
if(array_key_exists($userId, $userInfos))
|
|
|
|
$userInfo = $userInfos[$userId];
|
|
|
|
else
|
|
|
|
$userInfos[$userId] = $userInfo = User::byId((int)$userId);
|
2023-02-08 00:06:15 +00:00
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
$isPerma = $banInfo->isPermanent();
|
|
|
|
$list[] = [
|
2023-02-08 00:06:15 +00:00
|
|
|
'is_ban' => true,
|
2023-07-26 18:19:46 +00:00
|
|
|
'user_id' => $userId,
|
2023-02-08 00:06:15 +00:00
|
|
|
'user_name' => $userInfo->getUsername(),
|
|
|
|
'user_colour' => Colour::toMisuzu($userInfo->getColour()),
|
2023-07-26 18:19:46 +00:00
|
|
|
'ip_addr' => '::',
|
2023-02-08 00:06:15 +00:00
|
|
|
'is_perma' => $isPerma,
|
2023-07-26 18:19:46 +00:00
|
|
|
'expires' => date('c', $isPerma ? 0x7FFFFFFF : $banInfo->getExpiresTime())
|
2023-02-08 00:06:15 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
return $list;
|
2023-02-08 00:06:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getBanCheck($response, $request) {
|
|
|
|
if(!$request->hasHeader('X-SharpChat-Signature'))
|
|
|
|
return 400;
|
|
|
|
|
|
|
|
$userHash = (string)$request->getHeaderFirstLine('X-SharpChat-Signature');
|
|
|
|
$userTime = (int)$request->getParam('x', FILTER_SANITIZE_NUMBER_INT);
|
2022-09-13 13:14:49 +00:00
|
|
|
$ipAddress = (string)$request->getParam('a');
|
2023-02-08 00:06:15 +00:00
|
|
|
$userId = (string)$request->getParam('u');
|
|
|
|
$userIdIsName = (int)$request->getParam('n', FILTER_SANITIZE_NUMBER_INT);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
$realHash = hash_hmac('sha256', "check#{$userTime}#{$userId}#{$ipAddress}#{$userIdIsName}", $this->hashKey);
|
|
|
|
if(!hash_equals($realHash, $userHash) || $userTime < time() - 60)
|
|
|
|
return 403;
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
if($userIdIsName)
|
|
|
|
try {
|
|
|
|
$userInfo = User::byUsername($userId);
|
|
|
|
$userId = (string)$userInfo->getId();
|
|
|
|
} catch(RuntimeException $ex) {
|
|
|
|
$userId = '';
|
|
|
|
}
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
$banInfo = $this->bans->tryGetActiveBan($userId);
|
|
|
|
if($banInfo === null)
|
2023-02-08 00:06:15 +00:00
|
|
|
return ['is_ban' => false];
|
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
$isPerma = $banInfo->isPermanent();
|
2023-02-08 00:06:15 +00:00
|
|
|
|
|
|
|
return [
|
|
|
|
'is_ban' => true,
|
2023-07-26 18:19:46 +00:00
|
|
|
'user_id' => $banInfo->getUserId(),
|
|
|
|
'ip_addr' => '::',
|
2023-02-08 00:06:15 +00:00
|
|
|
'is_perma' => $isPerma,
|
2023-07-26 18:19:46 +00:00
|
|
|
'expires' => date('c', $isPerma ? 0x7FFFFFFF : $banInfo->getExpiresTime()),
|
2023-02-08 00:06:15 +00:00
|
|
|
];
|
2022-09-13 13:14:49 +00:00
|
|
|
}
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
public function postBanCreate($response, $request): int {
|
|
|
|
if(!$request->hasHeader('X-SharpChat-Signature') || !$request->isFormContent())
|
2022-09-13 13:14:49 +00:00
|
|
|
return 400;
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
$userHash = (string)$request->getHeaderFirstLine('X-SharpChat-Signature');
|
2022-09-13 13:14:49 +00:00
|
|
|
$content = $request->getContent();
|
2023-02-08 00:06:15 +00:00
|
|
|
$userTime = (int)$content->getParam('t', FILTER_SANITIZE_NUMBER_INT);
|
|
|
|
$userId = (string)$content->getParam('ui', FILTER_SANITIZE_NUMBER_INT);
|
|
|
|
$userAddr = (string)$content->getParam('ua');
|
|
|
|
$modId = (string)$content->getParam('mi', FILTER_SANITIZE_NUMBER_INT);
|
|
|
|
$modAddr = (string)$content->getParam('ma');
|
2022-09-13 13:14:49 +00:00
|
|
|
$duration = (int)$content->getParam('d', FILTER_SANITIZE_NUMBER_INT);
|
|
|
|
$isPermanent = (int)$content->getParam('p', FILTER_SANITIZE_NUMBER_INT);
|
|
|
|
$reason = (string)$content->getParam('r');
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
$signature = implode('#', [
|
|
|
|
'create', $userTime, $userId, $userAddr,
|
|
|
|
$modId, $modAddr, $duration, $isPermanent, $reason,
|
|
|
|
]);
|
|
|
|
|
|
|
|
$realHash = hash_hmac('sha256', $signature, $this->hashKey);
|
|
|
|
if(!hash_equals($realHash, $userHash) || $userTime < time() - 60)
|
2022-09-13 13:14:49 +00:00
|
|
|
return 403;
|
|
|
|
|
|
|
|
if(empty($reason))
|
|
|
|
$reason = 'Banned through chat.';
|
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
$comment = sprintf('User IP address: %s, Moderator IP address: %s', $userAddr, $modAddr);
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
if($isPermanent)
|
2023-07-26 18:19:46 +00:00
|
|
|
$expires = null;
|
|
|
|
else {
|
|
|
|
$now = time();
|
|
|
|
$expires = $now + $duration;
|
|
|
|
if($expires < $now)
|
|
|
|
return 400;
|
|
|
|
}
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
// IPs cannot be banned on their own
|
|
|
|
// substituting with the unused Railgun account for now.
|
2023-07-18 22:24:23 +00:00
|
|
|
if(empty($userId))
|
|
|
|
$userId = 69;
|
2023-02-08 00:06:15 +00:00
|
|
|
if(empty($modId))
|
|
|
|
$modId = 69;
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
try {
|
2023-02-08 00:06:15 +00:00
|
|
|
$modInfo = User::byId((int)$modId);
|
2023-07-22 15:02:41 +00:00
|
|
|
} catch(RuntimeException $ex) {
|
2022-09-13 13:14:49 +00:00
|
|
|
return 404;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2023-02-08 00:06:15 +00:00
|
|
|
$userInfo = User::byId((int)$userId);
|
2023-07-22 15:02:41 +00:00
|
|
|
} catch(RuntimeException $ex) {
|
2022-09-13 13:14:49 +00:00
|
|
|
return 404;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2023-07-26 18:19:46 +00:00
|
|
|
$this->bans->createBan(
|
2022-09-13 13:14:49 +00:00
|
|
|
$userInfo,
|
2023-07-26 18:19:46 +00:00
|
|
|
$expires,
|
2023-02-08 00:06:15 +00:00
|
|
|
$reason,
|
2023-07-26 18:19:46 +00:00
|
|
|
$comment,
|
|
|
|
modInfo: $modInfo
|
2022-09-13 13:14:49 +00:00
|
|
|
);
|
2023-07-22 15:02:41 +00:00
|
|
|
} catch(RuntimeException $ex) {
|
2022-09-13 13:14:49 +00:00
|
|
|
return 500;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 201;
|
|
|
|
}
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
public function deleteBanRevoke($response, $request): int {
|
|
|
|
if(!$request->hasHeader('X-SharpChat-Signature'))
|
|
|
|
return 400;
|
|
|
|
|
|
|
|
$userHash = (string)$request->getHeaderFirstLine('X-SharpChat-Signature');
|
|
|
|
$userTime = (int)$request->getParam('x', FILTER_SANITIZE_NUMBER_INT);
|
2022-09-13 13:14:49 +00:00
|
|
|
$type = (string)$request->getParam('t');
|
|
|
|
$subject = (string)$request->getParam('s');
|
|
|
|
|
2023-02-08 00:06:15 +00:00
|
|
|
$realHash = hash_hmac('sha256', "revoke#{$userTime}#{$type}#{$subject}", $this->hashKey);
|
|
|
|
if(!hash_equals($realHash, $userHash) || $userTime < time() - 60)
|
2022-09-13 13:14:49 +00:00
|
|
|
return 403;
|
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
if($type !== 'user')
|
|
|
|
return 404;
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
$banInfo = $this->bans->tryGetActiveBan($subject);
|
|
|
|
if($banInfo === null)
|
2022-09-13 13:14:49 +00:00
|
|
|
return 404;
|
|
|
|
|
2023-07-26 18:19:46 +00:00
|
|
|
$this->bans->deleteBans($banInfo);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
return 204;
|
|
|
|
}
|
|
|
|
}
|