feat(realtime): allow authentication via message
This commit is contained in:
parent
70a8b6b4cb
commit
371717abad
2 changed files with 85 additions and 12 deletions
|
@ -446,9 +446,90 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$server->onMessage(function (int $connection, string $message) use ($server) {
|
$server->onMessage(function (int $connection, string $message) use ($server, $register, $realtime, $containerId) {
|
||||||
$server->send([$connection], 'Sending messages is not allowed.');
|
try {
|
||||||
|
$db = $register->get('dbPool')->get();
|
||||||
|
$cache = $register->get('redisPool')->get();
|
||||||
|
|
||||||
|
$projectDB = new Database();
|
||||||
|
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
|
||||||
|
$projectDB->setNamespace('app_' . $realtime->connections[$connection]['projectId']);
|
||||||
|
$projectDB->setMocks(Config::getParam('collections', []));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Abuse Check
|
||||||
|
*
|
||||||
|
* Abuse limits are sending 32 times per minute and connection.
|
||||||
|
*/
|
||||||
|
$timeLimit = new TimeLimit('url:{url},conection:{connection}', 32, 60, $db);
|
||||||
|
$timeLimit
|
||||||
|
->setNamespace('app_' . $realtime->connections[$connection]['projectId'])
|
||||||
|
->setParam('{connection}', $connection)
|
||||||
|
->setParam('{container}', $containerId);
|
||||||
|
|
||||||
|
$abuse = new Abuse($timeLimit);
|
||||||
|
|
||||||
|
if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
||||||
|
throw new Exception('Too many messages', 1013);
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = json_decode($message, true);
|
||||||
|
|
||||||
|
if (is_null($message) || (!array_key_exists('type', $message) && !array_key_exists('data', $message))) {
|
||||||
|
$response = [
|
||||||
|
'code' => 1003,
|
||||||
|
'message' => 'Message format is wrong.'
|
||||||
|
];
|
||||||
$server->close($connection, 1003);
|
$server->close($connection, 1003);
|
||||||
|
$server->send([$connection], json_encode($response));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($message['type']) {
|
||||||
|
case 'authentication':
|
||||||
|
if (!array_key_exists('session', $message['data'])) {
|
||||||
|
throw new Exception('Payload not valid.', 1003);
|
||||||
|
}
|
||||||
|
|
||||||
|
$session = Auth::decodeSession($message['data']['session']);
|
||||||
|
Auth::$unique = $session['id'];
|
||||||
|
Auth::$secret = $session['secret'];
|
||||||
|
|
||||||
|
$user = $projectDB->getDocument(Auth::$unique);
|
||||||
|
|
||||||
|
if (
|
||||||
|
empty($user->getId()) // Check a document has been found in the DB
|
||||||
|
|| Database::SYSTEM_COLLECTION_USERS !== $user->getCollection() // Validate returned document is really a user document
|
||||||
|
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret) // Validate user has valid login token
|
||||||
|
) {
|
||||||
|
// cookie not valid
|
||||||
|
throw new Exception('Session not valid.', 1003);
|
||||||
|
}
|
||||||
|
|
||||||
|
$roles = Auth::getRoles($user);
|
||||||
|
$channels = Realtime::convertChannels(array_flip($realtime->connections[$connection]['channels']), $user->getId());
|
||||||
|
$realtime->subscribe($realtime->connections[$connection]['projectId'], $connection, $roles, $channels);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Exception('Message type not valid.', 1003);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
$response = [
|
||||||
|
'code' => $th->getCode(),
|
||||||
|
'message' => $th->getMessage()
|
||||||
|
];
|
||||||
|
|
||||||
|
$server->send([$connection], json_encode($response));
|
||||||
|
|
||||||
|
if ($th->getCode() === 1008) {
|
||||||
|
$server->close($connection, $th->getCode());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
$register->get('dbPool')->put($db);
|
||||||
|
$register->get('redisPool')->put($cache);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$server->onClose(function (int $connection) use ($realtime, $stats) {
|
$server->onClose(function (int $connection) use ($realtime, $stats) {
|
||||||
|
|
|
@ -226,18 +226,10 @@ class Realtime extends Adapter
|
||||||
if (!empty($userId)) {
|
if (!empty($userId)) {
|
||||||
$channels['account.' . $userId] = $value;
|
$channels['account.' . $userId] = $value;
|
||||||
}
|
}
|
||||||
unset($channels['account']);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\array_key_exists('account', $channels)) {
|
|
||||||
if ($userId) {
|
|
||||||
$channels['account.' . $userId] = $channels['account'];
|
|
||||||
}
|
|
||||||
unset($channels['account']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $channels;
|
return $channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue