Compare commits
3 Commits
aebe0c7549
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1bed0e7774 | |||
| 533fcaa498 | |||
| cae24c5c0c |
@@ -1,4 +1,3 @@
|
||||
vendor
|
||||
composer.json
|
||||
composer.lock
|
||||
storage/database.sqlite
|
||||
Generated
+4
-2
@@ -1,8 +1,10 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
|
||||
Generated
-12
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="database.sqlite" uuid="b6993544-8eca-46b7-9a38-b649d2563add">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/storage/database.sqlite</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+22
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="InertiaPackage">
|
||||
<option name="directoryPaths">
|
||||
<list />
|
||||
</option>
|
||||
</component>
|
||||
<component name="LaravelIdeaMainSettings">
|
||||
<option name="codeGeneration">
|
||||
<LaravelCodeGeneration>
|
||||
<option name="generationStringSettings">
|
||||
<map>
|
||||
<entry key="createEloquentScope:namespace" value="Models\Scopes" />
|
||||
<entry key="createModel:namespace" value="Models" />
|
||||
</map>
|
||||
</option>
|
||||
</LaravelCodeGeneration>
|
||||
</option>
|
||||
<option name="frameworkFound" value="true" />
|
||||
<option name="userClassName" value="\App\Models\User" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+17
-17
@@ -12,28 +12,28 @@
|
||||
</component>
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php83" />
|
||||
<path value="$PROJECT_DIR$/vendor/cboden/ratchet" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/stream" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/dns" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/promise" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/socket" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-message" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
|
||||
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-factory" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-message" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/promise" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/dns" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/stream" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/socket" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php83" />
|
||||
<path value="$PROJECT_DIR$/vendor/ratchet/rfc6455" />
|
||||
<path value="$PROJECT_DIR$/vendor/ralouphie/getallheaders" />
|
||||
<path value="$PROJECT_DIR$/vendor/cboden/ratchet" />
|
||||
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.5">
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.0">
|
||||
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
|
||||
@@ -65,7 +65,7 @@ class WebSocketServer implements MessageComponentInterface
|
||||
{
|
||||
$decodedMsg = json_decode($msg, true);
|
||||
if (!$decodedMsg) {
|
||||
$from->send("{\"error\"}: \"not or empty json\"");
|
||||
$from->send("{\"error\": \"not or empty json\"}");
|
||||
return;
|
||||
}
|
||||
$index = $this->getConnectionIndex($from);
|
||||
@@ -75,10 +75,10 @@ class WebSocketServer implements MessageComponentInterface
|
||||
$msgContent = $decodedMsg["message"] ?? null;
|
||||
if ($msgContent) {
|
||||
$this->sendToAllAuthenticated($this->connectionsData[$index]["username"], $msgContent);
|
||||
$from->send("{\"success\"}: \"message send\"");
|
||||
$from->send("{\"success\": \"message send\"}");
|
||||
return;
|
||||
}
|
||||
$from->send("{\"error\"}: \"no message\"");
|
||||
$from->send("{\"error\": \"no message\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,13 +87,13 @@ class WebSocketServer implements MessageComponentInterface
|
||||
$tokenUser = TokenHandler::getTokenOwnership($token);
|
||||
if ($tokenUser) {
|
||||
$this->connectionsData[$index]["username"] = $tokenUser;
|
||||
$from->send("{\"success\"}: \"authenticated\"");
|
||||
$from->send("{\"success\": \"authenticated\"}");
|
||||
return;
|
||||
}
|
||||
$from->send("{\"error\"}: \"invalid token\"");
|
||||
$from->send("{\"error\": \"invalid token\"}");
|
||||
return;
|
||||
}
|
||||
$from->send("{\"error\"}: \"you are not authenticated\"");
|
||||
$from->send("{\"error\": \"you are not authenticated\"}");
|
||||
}
|
||||
|
||||
public function onClose(ConnectionInterface $conn): void
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"require": {
|
||||
"cboden/ratchet": "^0.4.4",
|
||||
"ext-pdo": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ComCen\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
+218
-83
@@ -7,126 +7,261 @@ use ComCen\Html\Html;
|
||||
$html = new Html();
|
||||
$html->content = <<<'HTML'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ComCen</title>
|
||||
<style>
|
||||
body { font-family: monospace; max-width: 600px; margin: 40px auto; padding: 0 16px; }
|
||||
#log { border: 1px solid #ccc; height: 300px; overflow-y: auto; padding: 8px; margin-bottom: 8px; background: #f9f9f9; }
|
||||
.log-entry { margin: 2px 0; }
|
||||
.log-system { color: #888; }
|
||||
.log-error { color: #c00; }
|
||||
input, button { font-family: monospace; font-size: 14px; }
|
||||
#token { width: 100%; box-sizing: border-box; margin-bottom: 8px; padding: 4px; }
|
||||
#msg-row { display: flex; gap: 8px; }
|
||||
#message { flex: 1; padding: 4px; }
|
||||
button { padding: 4px 12px; cursor: pointer; }
|
||||
button:disabled { cursor: not-allowed; opacity: 0.5; }
|
||||
html{
|
||||
background: #666;
|
||||
font-family: monospace;
|
||||
}
|
||||
.hidden { display: none !important; }
|
||||
|
||||
/* Kontenery główne */
|
||||
#view-auth, #view-chat {
|
||||
margin-top: 5%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Nagłówki okien */
|
||||
.logotext {
|
||||
font-size: 24px;
|
||||
margin: 0px;
|
||||
color: #333;
|
||||
background-color: #ccc;
|
||||
border: 1px solid #000;
|
||||
border-bottom: none;
|
||||
width: 75%;
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
/* Główny boks (fioletowy) */
|
||||
.box {
|
||||
border: 1px solid #000;
|
||||
background-color: #88f;
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
/* Obszar logów / formularza */
|
||||
#log, .auth-content {
|
||||
border-bottom: 1px solid #000;
|
||||
height: 500px;
|
||||
background-color: #b0ebbb;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Stylizacja formularza wewnątrz zielonego pola */
|
||||
.auth-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* Elementy wiadomości i logów */
|
||||
#log div, .stat-msg-div {
|
||||
color: #000;
|
||||
background-color: #a9f;
|
||||
margin: 4px 10px;
|
||||
padding: 5px 6px;
|
||||
font-size: 12px;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
/* Inputy i Przyciski */
|
||||
input[type="text"], input[type="password"] {
|
||||
border: 1px solid #000;
|
||||
padding: 5px;
|
||||
width: 250px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
button {
|
||||
border: 1px solid #000;
|
||||
background: #ccc;
|
||||
cursor: pointer;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
#m-in {
|
||||
margin: 8px 0px 8px 8px;
|
||||
width: 77%;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.send, .logout {
|
||||
border: 1px solid #000;
|
||||
padding: 3px 0px;
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.send { margin: 8px -7px; border-left: none; }
|
||||
|
||||
.logout {
|
||||
float: right;
|
||||
border: none;
|
||||
border-left: 1px solid #000;
|
||||
height: 40px;
|
||||
background-color: #fcc;
|
||||
}
|
||||
|
||||
.logout:hover {
|
||||
background: #faa;
|
||||
}
|
||||
|
||||
/* Kolory systemowe */
|
||||
.error { background-color: #f66 !important; font-weight: bold; }
|
||||
.system { background-color: #66f !important; font-weight: bold; }
|
||||
|
||||
#auth-nav {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>ComCen</h2>
|
||||
|
||||
<input id="token" type="text" placeholder="Paste token from curl login/register here" />
|
||||
<div style="display:flex; gap:8px; margin-bottom:8px;">
|
||||
<button id="connect-btn" onclick="connect()">Connect</button>
|
||||
<button id="disconnect-btn" onclick="disconnect()" disabled>Disconnect</button>
|
||||
<div id="view-auth">
|
||||
<h2 class="logotext">ComCen - Terminal Autoryzacji</h2>
|
||||
<div class="box">
|
||||
<div class="auth-content">
|
||||
<div id="auth-nav">
|
||||
<button onclick="showAuth('login')">LOGIN</button>
|
||||
<button onclick="showAuth('reg')">REGISTER</button>
|
||||
</div>
|
||||
|
||||
<div id="form-login">
|
||||
<input type="text" id="l-u" placeholder="Użytkownik">
|
||||
<br><br>
|
||||
<input type="password" id="l-p" placeholder="Hasło">
|
||||
<br><br>
|
||||
<button onclick="runAuth('login')" style="width: 100%">ZALOGUJ</button>
|
||||
</div>
|
||||
|
||||
<div id="form-reg" class="hidden">
|
||||
<input type="text" id="r-u" placeholder="Nowy login (a-z, 0-9)">
|
||||
<br><br>
|
||||
<input type="password" id="r-p" placeholder="Hasło">
|
||||
<br><br>
|
||||
<button onclick="runAuth('register')" style="width: 100%">ZAREJESTRUJ</button>
|
||||
</div>
|
||||
|
||||
<div id="stat-msg" class="stat-msg-div hidden"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="view-chat" class="hidden">
|
||||
<h2 class="logotext">ComCen - IRC - Zalogowany jako: <span id="current-user"></span></h2>
|
||||
<div class="box">
|
||||
<div id="log"></div>
|
||||
|
||||
<div id="msg-row">
|
||||
<input id="message" type="text" placeholder="Message..." disabled onkeydown="if(event.key==='Enter') send()" />
|
||||
<button id="send-btn" onclick="send()" disabled>Send</button>
|
||||
<input type="text" id="m-in" placeholder="Wiadomość..." onkeydown="if(event.key==='Enter') send()">
|
||||
<button class="send" onclick="send()">Wyślij</button>
|
||||
<button class="logout" onclick="location.reload()">Wyloguj</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
<script>
|
||||
const API = "http://localhost:8080";
|
||||
let ws = null;
|
||||
let authenticated = false;
|
||||
let myToken = "";
|
||||
|
||||
function log(text, type = '') {
|
||||
function showAuth(mode) {
|
||||
document.getElementById('form-login').classList.toggle('hidden', mode !== 'login');
|
||||
document.getElementById('form-reg').classList.toggle('hidden', mode !== 'reg');
|
||||
document.getElementById('stat-msg').classList.add('hidden');
|
||||
}
|
||||
|
||||
function addLog(txt, cls = '') {
|
||||
const log = document.getElementById('log');
|
||||
const div = document.createElement('div');
|
||||
div.className = 'log-entry' + (type ? ' log-' + type : '');
|
||||
div.textContent = text;
|
||||
if(cls) div.className = cls;
|
||||
div.textContent = txt;
|
||||
log.appendChild(div);
|
||||
log.scrollTop = log.scrollHeight;
|
||||
}
|
||||
|
||||
function setConnected(connected) {
|
||||
document.getElementById('connect-btn').disabled = connected;
|
||||
document.getElementById('disconnect-btn').disabled = !connected;
|
||||
}
|
||||
async function runAuth(type) {
|
||||
const msgDiv = document.getElementById('stat-msg');
|
||||
const u = document.getElementById(type === 'login' ? 'l-u' : 'r-u').value.trim();
|
||||
const p = document.getElementById(type === 'login' ? 'l-p' : 'r-p').value.trim();
|
||||
|
||||
function setAuthenticated(auth) {
|
||||
authenticated = auth;
|
||||
document.getElementById('message').disabled = !auth;
|
||||
document.getElementById('send-btn').disabled = !auth;
|
||||
}
|
||||
|
||||
function connect() {
|
||||
const token = document.getElementById('token').value.trim();
|
||||
if (!token) {
|
||||
log('Enter a token first.', 'error');
|
||||
if (type === 'register') {
|
||||
const regex = /^[a-zA-Z0-9_\.]+$/;
|
||||
if (!regex.test(u)) {
|
||||
msgDiv.textContent = "Błąd: Niepoprawne znaki!";
|
||||
msgDiv.className = "stat-msg-div error";
|
||||
msgDiv.classList.remove('hidden');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ws = new WebSocket('ws://localhost:8080/ws');
|
||||
|
||||
ws.onopen = () => {
|
||||
log('Connected. Authenticating...', 'system');
|
||||
setConnected(true);
|
||||
ws.send(JSON.stringify({ token }));
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const text = event.data;
|
||||
if (text === '{"success"}: "authenticated"') {
|
||||
log('Authenticated.', 'system');
|
||||
setAuthenticated(true);
|
||||
} else if (text === '{"error"}: "invalid token"') {
|
||||
log('Invalid token. Connection closed.', 'error');
|
||||
ws.close();
|
||||
} else if (text === '{"error"}: "you are not authenticated"') {
|
||||
log('Server: not authenticated', 'error');
|
||||
} else {
|
||||
try {
|
||||
const data = JSON.parse(text);
|
||||
log(`${data.sender}: ${data.msg}`);
|
||||
} catch {
|
||||
log(text);
|
||||
const res = await fetch(`${API}/${type}?username=${encodeURIComponent(u)}&password=${encodeURIComponent(p)}`);
|
||||
const data = await res.json();
|
||||
|
||||
if (type === 'login' && data.token) {
|
||||
myToken = data.token;
|
||||
document.getElementById('current-user').textContent = u;
|
||||
document.getElementById('view-auth').classList.add('hidden');
|
||||
document.getElementById('view-chat').classList.remove('hidden');
|
||||
startWS();
|
||||
} else if (type === 'register' && data.error === 'none') {
|
||||
msgDiv.textContent = "Konto utworzone. Zaloguj się.";
|
||||
msgDiv.className = "stat-msg-div system";
|
||||
msgDiv.classList.remove('hidden');
|
||||
showAuth('login');
|
||||
} else {
|
||||
msgDiv.textContent = "Błąd: " + (data.error || "odmowa");
|
||||
msgDiv.className = "stat-msg-div error";
|
||||
msgDiv.classList.remove('hidden');
|
||||
}
|
||||
} catch (e) {
|
||||
msgDiv.textContent = "Błąd połączenia z API";
|
||||
msgDiv.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function startWS() {
|
||||
ws = new WebSocket("ws://localhost:8080/ws");
|
||||
ws.onopen = () => ws.send(JSON.stringify({ token: myToken }));
|
||||
|
||||
ws.onmessage = (e) => {
|
||||
try {
|
||||
const d = JSON.parse(e.data);
|
||||
if (d.success) {
|
||||
if (d.success.includes("authenticated")) addLog("Połączono pomyślnie z czatem.", "system");
|
||||
return;
|
||||
}
|
||||
if (d.sender && d.msg) addLog(`${d.sender}: ${d.msg}`);
|
||||
else if (d.error) addLog("Błąd: " + d.error, "error");
|
||||
} catch (err) { console.error("Błąd parsowania:", e.data); }
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
log('Disconnected.', 'system');
|
||||
setConnected(false);
|
||||
setAuthenticated(false);
|
||||
ws = null;
|
||||
addLog("Połączenie przerwane.", "error");
|
||||
document.getElementById('m-in').disabled = true;
|
||||
};
|
||||
|
||||
ws.onerror = () => {
|
||||
log('WebSocket error.', 'error');
|
||||
};
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
if (ws) ws.close();
|
||||
}
|
||||
|
||||
function send() {
|
||||
const input = document.getElementById('message');
|
||||
const text = input.value.trim();
|
||||
if (!text || !ws || !authenticated) return;
|
||||
ws.send(JSON.stringify({ message: text }));
|
||||
log(`You: ${text}`);
|
||||
input.value = '';
|
||||
const input = document.getElementById('m-in');
|
||||
if(input.value.trim() && ws && ws.readyState === 1) {
|
||||
ws.send(JSON.stringify({ message: input.value }));
|
||||
addLog("Ty: " + input.value);
|
||||
input.value = "";
|
||||
}
|
||||
</script>
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
HTML;
|
||||
$html->renderContent();
|
||||
@@ -13,10 +13,17 @@ class LoginController implements HttpServerInterface
|
||||
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null): void
|
||||
{
|
||||
$params = [];
|
||||
parse_str($request->getUri()->getQuery(), $params);
|
||||
|
||||
if (empty($params["username"]) && empty($params["password"])) {
|
||||
Utils::respondHtml($conn, $this->loginPage());
|
||||
$conn->close();
|
||||
return;
|
||||
}
|
||||
|
||||
$login = true;
|
||||
$responseHead = "";
|
||||
$json = "";
|
||||
parse_str($request->getUri()->getQuery(), $params);
|
||||
|
||||
$username = $params["username"];
|
||||
$password = $params["password"];
|
||||
@@ -49,6 +56,62 @@ class LoginController implements HttpServerInterface
|
||||
$conn->close();
|
||||
}
|
||||
|
||||
private function loginPage(): string
|
||||
{
|
||||
return <<<'HTML'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Login — ComCen</title>
|
||||
<style>
|
||||
body { font-family: monospace; max-width: 360px; margin: 80px auto; padding: 0 16px; }
|
||||
h2 { margin-bottom: 24px; }
|
||||
input { width: 100%; box-sizing: border-box; padding: 6px; font-family: monospace; font-size: 14px; margin-bottom: 10px; border: 1px solid #ccc; }
|
||||
button { padding: 6px 16px; font-family: monospace; font-size: 14px; cursor: pointer; }
|
||||
#msg { margin-top: 12px; font-size: 13px; }
|
||||
.error { color: #c00; }
|
||||
#token-box { margin-top: 16px; display: none; }
|
||||
#token-box p { margin: 0 0 6px; }
|
||||
#token-val { width: 100%; box-sizing: border-box; padding: 6px; font-family: monospace; font-size: 12px; background: #f4f4f4; border: 1px solid #ccc; }
|
||||
a { color: inherit; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Login</h2>
|
||||
<input id="username" type="text" placeholder="Username" />
|
||||
<input id="password" type="password" placeholder="Password" />
|
||||
<button onclick="login()">Login</button>
|
||||
<div id="msg"></div>
|
||||
<div id="token-box">
|
||||
<p>Your token (paste into chat):</p>
|
||||
<input id="token-val" type="text" readonly onclick="this.select()" />
|
||||
</div>
|
||||
<p><a href="/register">No account? Register</a></p>
|
||||
<script>
|
||||
async function login() {
|
||||
const u = document.getElementById('username').value.trim();
|
||||
const p = document.getElementById('password').value.trim();
|
||||
const msg = document.getElementById('msg');
|
||||
if (!u || !p) { msg.className = 'error'; msg.textContent = 'Fill in all fields.'; return; }
|
||||
msg.textContent = '';
|
||||
const res = await fetch('/login?username=' + encodeURIComponent(u) + '&password=' + encodeURIComponent(p));
|
||||
const data = await res.json();
|
||||
if (data.token) {
|
||||
document.getElementById('token-val').value = data.token;
|
||||
document.getElementById('token-box').style.display = 'block';
|
||||
} else {
|
||||
msg.className = 'error';
|
||||
msg.textContent = data.error || 'Login failed.';
|
||||
}
|
||||
}
|
||||
document.addEventListener('keydown', e => { if (e.key === 'Enter') login(); });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
}
|
||||
|
||||
public function onMessage(ConnectionInterface $from, $msg): void {}
|
||||
public function onClose(ConnectionInterface $conn): void {}
|
||||
public function onError(ConnectionInterface $conn, \Exception $e): void { $conn->close(); }
|
||||
|
||||
@@ -12,10 +12,17 @@ class RegisterController implements HttpServerInterface
|
||||
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null): void
|
||||
{
|
||||
$params = [];
|
||||
parse_str($request->getUri()->getQuery(), $params);
|
||||
|
||||
if (empty($params["username"]) && empty($params["password"])) {
|
||||
Utils::respondHtml($conn, $this->registerPage());
|
||||
$conn->close();
|
||||
return;
|
||||
}
|
||||
|
||||
$createAccount = true;
|
||||
$responseHead = "";
|
||||
$json = "";
|
||||
parse_str($request->getUri()->getQuery(), $params);
|
||||
|
||||
$username = $params["username"];
|
||||
$password = $params["password"];
|
||||
@@ -53,6 +60,57 @@ class RegisterController implements HttpServerInterface
|
||||
$conn->close();
|
||||
}
|
||||
|
||||
private function registerPage(): string
|
||||
{
|
||||
return <<<'HTML'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Register — ComCen</title>
|
||||
<style>
|
||||
body { font-family: monospace; max-width: 360px; margin: 80px auto; padding: 0 16px; }
|
||||
h2 { margin-bottom: 24px; }
|
||||
input { width: 100%; box-sizing: border-box; padding: 6px; font-family: monospace; font-size: 14px; margin-bottom: 10px; border: 1px solid #ccc; }
|
||||
button { padding: 6px 16px; font-family: monospace; font-size: 14px; cursor: pointer; }
|
||||
#msg { margin-top: 12px; font-size: 13px; }
|
||||
.error { color: #c00; }
|
||||
.success { color: #080; }
|
||||
a { color: inherit; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Register</h2>
|
||||
<input id="username" type="text" placeholder="Username" />
|
||||
<input id="password" type="password" placeholder="Password (min 5 chars)" />
|
||||
<button onclick="register()">Register</button>
|
||||
<div id="msg"></div>
|
||||
<p><a href="/login">Already have an account? Login</a></p>
|
||||
<script>
|
||||
async function register() {
|
||||
const u = document.getElementById('username').value.trim();
|
||||
const p = document.getElementById('password').value.trim();
|
||||
const msg = document.getElementById('msg');
|
||||
if (!u || !p) { msg.className = 'error'; msg.textContent = 'Fill in all fields.'; return; }
|
||||
msg.textContent = '';
|
||||
const res = await fetch('/register?username=' + encodeURIComponent(u) + '&password=' + encodeURIComponent(p));
|
||||
const data = await res.json();
|
||||
if (data.error === 'none') {
|
||||
msg.className = 'success';
|
||||
msg.textContent = 'Account created! Redirecting to login...';
|
||||
setTimeout(() => window.location.href = '/login', 1200);
|
||||
} else {
|
||||
msg.className = 'error';
|
||||
msg.textContent = data.error || 'Registration failed.';
|
||||
}
|
||||
}
|
||||
document.addEventListener('keydown', e => { if (e.key === 'Enter') register(); });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
}
|
||||
|
||||
public function onMessage(ConnectionInterface $from, $msg): void {}
|
||||
public function onClose(ConnectionInterface $conn): void {}
|
||||
public function onError(ConnectionInterface $conn, \Exception $e): void { $conn->close(); }
|
||||
|
||||
+13
-1
@@ -4,10 +4,22 @@ namespace ComCen\Http;
|
||||
|
||||
use Ratchet\ConnectionInterface;
|
||||
|
||||
/*
|
||||
Access-Control-Allow-Origin: *
|
||||
zezwala na urzycie portu 8080
|
||||
portalowi chodzącemu na porcie 8000
|
||||
*/
|
||||
|
||||
|
||||
class Utils
|
||||
{
|
||||
static function responeJson(ConnectionInterface $conn, string $head, string $jsonData): void
|
||||
{
|
||||
$conn->send("HTTP/1.1 {$head}\r\nContent-Type: application/json\r\n\r\n{$jsonData}");
|
||||
$conn->send("HTTP/1.1 {$head}\r\nContent-Type: application/json\r\nAccess-Control-Allow-Origin: *\r\n\r\n{$jsonData}");
|
||||
}
|
||||
|
||||
static function respondHtml(ConnectionInterface $conn, string $html): void
|
||||
{
|
||||
$conn->send("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nAccess-Control-Allow-Origin: *\r\n\r\n{$html}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user