project(ttyd)
-set(LIBWEBSOCKETS_MIN_VERSION 1.6)
+set(LIBWEBSOCKETS_MIN_VERSION 1.7.0)
set(SOURCE_FILES src/server.c src/http.c src/protocol.c src/utils.c)
find_package(OpenSSL REQUIRED)
--signal, -s Signal to send to the command when exit it (default: SIGHUP)
--reconnect, -r Time to reconnect for the client in seconds (default: 10)
--readonly, -R Do not allow clients to write to the TTY
+ --check-origin, -O Do not allow websocket connection from different origin
--once, -o Accept only one client and exit on disconnection
--ssl, -S Enable ssl
--ssl-cert, -C Ssl certificate file path
term.installKeyboard();
};
- term.decorate(document.getElementById("terminal"));
+ var termContainer = document.getElementById('terminal');
+ while (termContainer.firstChild) {
+ termContainer.removeChild(termContainer.firstChild);
+ }
+ term.decorate(termContainer);
};
ws.onmessage = function(event) {
- data = event.data.slice(1);
+ var data = event.data.slice(1);
switch(event.data[0]) {
case '0':
term.io.writeUTF8(window.atob(data));
var errorNode = document.createElement('div');
errorNode.style.cssText = [
"color: red",
+ "background-color: white",
"font-size: x-large",
"opacity: 0.75",
"text-align: center",
"border: 0.1em dotted #ccc"
].join(";");
errorNode.textContent = "Websocket handshake failed!";
- document.getElementById("terminal").appendChild(errorNode);
+ document.getElementById('terminal').appendChild(errorNode);
};
};
-
var sendPing = function(ws) {
ws.send("1");
};
return size;
}
+bool
+check_host_origin(struct lws *wsi) {
+ int origin_length = lws_hdr_total_length(wsi, WSI_TOKEN_ORIGIN);
+ char buf[origin_length + 1];
+ memset(buf, 0, sizeof(buf));
+ int len = lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_ORIGIN);
+ if (len > 0) {
+ const char *prot, *address, *path;
+ int port;
+ if (lws_parse_uri(buf, &prot, &address, &port, &path))
+ return false;
+ sprintf(buf, "%s:%d", address, port);
+ int host_length = lws_hdr_total_length(wsi, WSI_TOKEN_HOST);
+ if (host_length != strlen(buf))
+ return false;
+ char host_buf[host_length + 1];
+ memset(host_buf, 0, sizeof(host_buf));
+ len = lws_hdr_copy(wsi, host_buf, sizeof(host_buf), WSI_TOKEN_HOST);
+ return len > 0 && strcasecmp(buf, host_buf) == 0;
+ }
+ return false;
+}
+
void
tty_client_destroy(struct tty_client *client) {
if (client->exit || client->pid <= 0)
lwsl_notice("refuse to serve new client due to the --once option.\n");
return -1;
}
+ if (server->check_origin && !check_host_origin(wsi)) {
+ lwsl_notice("refuse to serve new client from different origin due to the --check-origin option.\n");
+ return -1;
+ }
break;
case LWS_CALLBACK_ESTABLISHED:
client->exit = false;
{"ssl-key", required_argument, NULL, 'K'},
{"ssl-ca", required_argument, NULL, 'A'},
{"readonly", no_argument, NULL, 'R'},
+ {"check-origin", no_argument, NULL, 'O'},
{"once", no_argument, NULL, 'o'},
{"debug", required_argument, NULL, 'd'},
{"version", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, 0, 0}
};
-static const char *opt_string = "p:i:c:u:g:s:r:aSC:K:A:Rod:vh";
+static const char *opt_string = "p:i:c:u:g:s:r:aSC:K:A:ROod:vh";
void print_help() {
fprintf(stderr, "ttyd is a tool for sharing terminal over the web\n\n"
" --signal, -s Signal to send to the command when exit it (default: SIGHUP)\n"
" --reconnect, -r Time to reconnect for the client in seconds (default: 10)\n"
" --readonly, -R Do not allow clients to write to the TTY\n"
+ " --check-origin, -O Do not allow websocket connection from different origin\n"
" --once, -o Accept only one client and exit on disconnection\n"
" --ssl, -S Enable ssl\n"
" --ssl-cert, -C Ssl certificate file path\n"
case 'R':
server->readonly = true;
break;
+ case 'O':
+ server->check_origin = true;
+ break;
case 'o':
server->once = true;
break;
lwsl_notice(" start command: %s\n", server->command);
lwsl_notice(" reconnect timeout: %ds\n", server->reconnect);
lwsl_notice(" close signal: %s (%d)\n", server->sig_name, server->sig_code);
+ if (server->check_origin)
+ lwsl_notice(" check origin: true\n");
if (server->readonly)
lwsl_notice(" readonly: true\n");
if (server->once)
int sig_code; // close signal
char *sig_name; // human readable signal string
bool readonly; // whether not allow clients to write to the TTY
+ bool check_origin; // whether allow websocket connection from different origin
bool once; // whether accept only one client and exit on disconnection
pthread_mutex_t lock;
};