Skip to content

Commit 020f73f

Browse files
committed
Make chat example more robust against XSS etc.
1 parent a803854 commit 020f73f

3 files changed

Lines changed: 42 additions & 33 deletions

File tree

examples/10-eventsource.html

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22
<html>
33
<head>
44
<meta charset="utf-8"/>
5-
<title>EventSource example</title>
5+
<title>EventSource Chat</title>
66
<script>
7-
var es = new EventSource('demo'), username = '';
7+
var es = new EventSource('chat'), username = '';
88
es.addEventListener('message', function(event) {
99
var data = JSON.parse(event.data);
10-
var $messages = document.querySelectorAll('.chat-messages')[0];
10+
1111
var message = document.createElement('div');
12-
if (data.username !== '') {
13-
message.innerHTML = `<strong>${data.username}:</strong> ${data.message}`;
14-
} else {
15-
message.innerHTML = data.message;
12+
if (data.username) {
13+
var strong = document.createElement('strong');
14+
strong.appendChild(document.createTextNode(data.username));
15+
message.appendChild(strong);
1616
}
17+
message.appendChild(document.createTextNode(data.message));
1718
message.classList.add('chat-message');
19+
20+
var $messages = document.querySelector('.chat-messages');
1821
if ($messages.childNodes.length !== 0) {
1922
$messages.insertBefore(message, $messages.firstChild);
2023
} else {
@@ -23,31 +26,29 @@
2326
});
2427

2528
document.addEventListener('DOMContentLoaded', function() {
26-
var $chatForm = document.querySelectorAll('.chat-form')[0];
29+
var $chatForm = document.querySelector('.chat-form');
2730
$chatForm.addEventListener('submit', function($event) {
2831
$event.preventDefault();
29-
var $input = document.querySelectorAll('.chat-form input')[0];
32+
var $input = document.querySelector('.chat-form input');
3033
if ($input.value.length) {
31-
fetch(`/message?message=${$input.value}&username=${username}`).then(function() {
34+
fetch('/message?message=' + encodeURIComponent($input.value) + '&username=' + encodeURIComponent(username)).then(function() {
3235
$input.value = '';
3336
});
3437
}
3538
});
36-
});
3739

38-
document.addEventListener('DOMContentLoaded', function() {
39-
var $chatForm = document.querySelectorAll('.username-form')[0];
40+
var $chatForm = document.querySelector('.username-form');
4041
$chatForm.addEventListener('submit', function($event) {
4142
$event.preventDefault();
42-
var $input = document.querySelectorAll('.username-form input')[0];
43+
var $input = document.querySelector('.username-form input');
4344
if ($input.value.length > 3) {
4445
document.activeElement.blur();
4546
username = $input.value;
46-
document.querySelectorAll('.chat-header')[0].innerHTML = username;
47+
document.querySelector('.chat-header').innerText = username;
4748
document.body.classList.add('hide-username');
4849
setTimeout(function() {
49-
document.querySelectorAll('.username-form-container')[0].style.display = 'none';
50-
document.querySelectorAll('.chat-form input')[0].focus();
50+
document.querySelector('.username-form-container').style.display = 'none';
51+
document.querySelector('.chat-form input').focus();
5152
}, 800);
5253
}
5354
});
@@ -69,7 +70,7 @@
6970
</div>
7071
<div class="username-form-container">
7172
<form class="username-form">
72-
<input type="text" placeholder="Enter username" autofocus="">
73+
<input type="text" placeholder="Enter username" autofocus>
7374
<button type="submit">Enter</button>
7475
</form>
7576
</div>

examples/10-styles.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ form input {
8787
border-top: 1px solid #e9e9e9;
8888
}
8989

90+
.chat-message strong {
91+
margin-right: 0.5rem;
92+
}
93+
9094
.username-form-container {
9195
transition: opacity 0.15s linear 0.55s;
9296
position: absolute;

examples/11-chat.php

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,41 +13,45 @@
1313

1414
$http = new React\Http\Server($socket);
1515
$http->on('request', function (Request $request, Response $response) use ($channel) {
16-
1716
switch ($request->getPath()) {
1817
case '/':
1918
$response->writeHead('200', array('Content-Type' => 'text/html'));
2019
$response->end(file_get_contents(__DIR__ . '/10-eventsource.html'));
21-
$message = array('message' => 'New person connected from '. $request->remoteAddress, 'username' => '');
22-
$channel->writeMessage(json_encode($message));
20+
2321
return;
2422
case '/styles.css':
2523
$response->writeHead('200', array('Content-Type' => 'text/css'));
2624
$response->end(file_get_contents(__DIR__ . '/10-styles.css'));
2725
return;
2826
case '/message':
2927
$query = $request->getQuery();
30-
if (array_key_exists('message', $query)) {
31-
$message = array('message' => htmlspecialchars($query['message']), 'username' => htmlspecialchars($query['username']));
28+
if (isset($query['username'], $query['message'])) {
29+
$message = array('message' => $query['message'], 'username' =>$query['username']);
3230
$channel->writeMessage(json_encode($message));
3331
}
3432
$response->writeHead('201', array('Content-Type' => 'text/json'));
3533
$response->end();
3634
return;
37-
}
35+
case '/chat':
36+
$id = $request->getHeaderLine('Last-Event-ID');
3837

39-
echo $request->remoteAddress . ' connected' . PHP_EOL;
38+
$response->writeHead(200, array('Content-Type' => 'text/event-stream'));
39+
$channel->connect($response, $id);
4040

41-
$headers = $request->getHeaders();
42-
$id = isset($headers['Last-Event-ID']) ? $headers['Last-Event-ID'] : null;
41+
$message = array('message' => 'New person connected from '. $request->remoteAddress);
42+
$channel->writeMessage(json_encode($message));
4343

44-
$response->writeHead(200, array('Content-Type' => 'text/event-stream'));
45-
$channel->connect($response, $id);
44+
$response->on('close', function () use ($response, $channel, $request) {
45+
$channel->disconnect($response);
4646

47-
$response->on('close', function () use ($response, $channel, $request) {
48-
echo $request->remoteAddress . 'disconnected' . PHP_EOL;
49-
$channel->disconnect($response);
50-
});
47+
$message = array('message' => 'Bye '. $request->remoteAddress);
48+
$channel->writeMessage(json_encode($message));
49+
});
50+
break;
51+
default:
52+
$response->writeHead(404);
53+
$response->end('Not Found');
54+
}
5155
});
5256

5357
$socket->listen(isset($argv[1]) ? $argv[1] : 0, '0.0.0.0');

0 commit comments

Comments
 (0)