From ae837910da4b18601ef856812a3128dcb139d6b3 Mon Sep 17 00:00:00 2001 From: Shuanglei Tao Date: Sat, 22 Jun 2019 18:01:15 +0800 Subject: [PATCH] http: add basic auth support back --- html/src/components/terminal/index.tsx | 11 ++- src/http.c | 118 ++++++++++++++----------- src/index.html | 2 +- 3 files changed, 77 insertions(+), 54 deletions(-) diff --git a/html/src/components/terminal/index.tsx b/html/src/components/terminal/index.tsx index 2f159ed..597294f 100644 --- a/html/src/components/terminal/index.tsx +++ b/html/src/components/terminal/index.tsx @@ -7,6 +7,12 @@ import { OverlayAddon } from './overlay'; import 'xterm/dist/xterm.css'; +export interface IWindowWithTerminal extends Window { + term: Terminal; + tty_auth_token?: string; +} +declare let window: IWindowWithTerminal; + const enum Command { // server side OUTPUT = '0', @@ -86,7 +92,7 @@ export default class Xterm extends Component { this.socket = new WebSocket(this.props.url, ['tty']); this.terminal = new Terminal(this.props.options); const { socket, terminal, container, fitAddon, overlayAddon } = this; - (window as any).term = terminal; + window.term = terminal; socket.binaryType = 'arraybuffer'; socket.onopen = this.onSocketOpen; @@ -121,8 +127,9 @@ export default class Xterm extends Component { private onSocketOpen() { console.log('[ttyd] Websocket connection opened'); const { socket, textEncoder, fitAddon } = this; + const authToken = window.tty_auth_token; - socket.send(textEncoder.encode(JSON.stringify({AuthToken: ''}))); + socket.send(textEncoder.encode(JSON.stringify({AuthToken: authToken}))); fitAddon.fit(); } diff --git a/src/http.c b/src/http.c index 38a94e3..2a5d092 100644 --- a/src/http.c +++ b/src/http.c @@ -4,10 +4,14 @@ #include "server.h" #include "html.h" +enum { + AUTH_OK, AUTH_FAIL, AUTH_ERROR +}; + int -check_auth(struct lws *wsi) { +check_auth(struct lws *wsi, struct pss_http *pss) { if (server->credential == NULL) - return 0; + return AUTH_OK; int hdr_length = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION); char buf[hdr_length + 1]; @@ -26,54 +30,64 @@ check_auth(struct lws *wsi) { } } if (b64_text != NULL && !strcmp(b64_text, server->credential)) - return 0; + return AUTH_OK; } unsigned char buffer[1024 + LWS_PRE], *p, *end; p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; + char *body = strdup("401 Unauthorized\n"); + size_t n = strlen(body); + if (lws_add_http_header_status(wsi, HTTP_STATUS_UNAUTHORIZED, &p, end)) - return 1; + return AUTH_ERROR; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_WWW_AUTHENTICATE, (unsigned char *) "Basic realm=\"ttyd\"", 18, &p, end)) - return 1; - if (lws_add_http_header_content_length(wsi, 0, &p, end)) - return 1; + return AUTH_ERROR; + if (lws_add_http_header_content_length(wsi, n, &p, end)) + return AUTH_ERROR; if (lws_finalize_http_header(wsi, &p, end)) - return 1; + return AUTH_ERROR; if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) - return 1; + return AUTH_ERROR; + + pss->buffer = pss->ptr = body; + pss->len = n; + lws_callback_on_writable(wsi); - return -1; + return AUTH_FAIL; +} + +void access_log(struct lws *wsi, const char *path) { + char name[100], rip[50]; +#if LWS_LIBRARY_VERSION_MAJOR >=2 && LWS_LIBRARY_VERSION_MINOR >=4 + struct lws *n_wsi = lws_get_network_wsi(wsi); +#else + struct lws *n_wsi = wsi; +#endif + lws_get_peer_addresses(wsi, lws_get_socket_fd(n_wsi), name, sizeof(name), rip, sizeof(rip)); + lwsl_notice("HTTP %s - %s (%s)\n", path, rip, name); } int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct pss_http *pss = (struct pss_http *) user; unsigned char buffer[4096 + LWS_PRE], *p, *end; - char buf[256], name[100], rip[50]; + char buf[256]; switch (reason) { case LWS_CALLBACK_HTTP: - // only GET method is allowed - if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) || len < 1) { - lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); - goto try_to_reuse; - } - - snprintf(pss->path, sizeof(pss->path), "%s", (const char *)in); - lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, sizeof(name), rip, sizeof(rip)); - lwsl_notice("HTTP %s - %s (%s)\n", (char *) in, rip, name); - - switch (check_auth(wsi)) { - case 0: + access_log(wsi, (const char *) in); + snprintf(pss->path, sizeof(pss->path), "%s", (const char *) in); + switch (check_auth(wsi, pss)) { + case AUTH_OK: break; - case -1: - goto try_to_reuse; - case 1: + case AUTH_FAIL: + return 0; + case AUTH_ERROR: default: return 1; } @@ -82,8 +96,8 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, voi end = p + sizeof(buffer) - LWS_PRE; if (strncmp(pss->path, "/auth_token.js", 14) == 0) { - size_t n = server->credential != NULL ? sprintf(buf, "var tty_auth_token = '%s';", server->credential) : 0; - + const char *credential = server->credential != NULL ? server->credential : ""; + size_t n = sprintf(buf, "var tty_auth_token = '%s';\n", credential); if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, @@ -97,13 +111,10 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, voi return 1; if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) return 1; - if (n > 0) { - pss->buffer = pss->ptr = strdup(buf); - pss->len = n; - lws_callback_on_writable(wsi); - break; - } - goto try_to_reuse; + pss->buffer = pss->ptr = strdup(buf); + pss->len = n; + lws_callback_on_writable(wsi); + break; } if (strcmp(pss->path, "/") != 0) { @@ -134,26 +145,31 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, voi break; case LWS_CALLBACK_HTTP_WRITEABLE: - if (pss->len <= 0) - goto try_to_reuse; - - if (pss ->ptr - pss->buffer == pss->len) { - if (pss->buffer != (char *) index_html) free(pss->buffer); + if (!pss->buffer || pss->len <= 0) { goto try_to_reuse; } - int n = sizeof(buffer) - LWS_PRE; - if (pss->ptr - pss->buffer + n > pss->len) - n = (int) (pss->len - (pss->ptr - pss->buffer)); - memcpy(buffer + LWS_PRE, pss->ptr, n); - pss->ptr += n; - if (lws_write_http(wsi, buffer + LWS_PRE, (size_t) n) < n) { - if (pss->buffer != (char *) index_html) free(pss->buffer); - return -1; - } + do { + int n = sizeof(buffer) - LWS_PRE; + int m = lws_get_peer_write_allowance(wsi); + if (m == 0) { + lws_callback_on_writable(wsi); + return 0; + } else if (m != -1 && m < n) { + n = m; + } + if (pss->ptr + n > pss->buffer + pss->len) + n = (int) (pss->len - (pss->ptr - pss->buffer)); + memcpy(buffer + LWS_PRE, pss->ptr, n); + pss->ptr += n; + if (lws_write_http(wsi, buffer + LWS_PRE, (size_t) n) < n) { + if (pss->buffer != (char *) index_html) free(pss->buffer); + return -1; + } + } while (!lws_send_pipe_choked(wsi) && pss->ptr != pss->buffer + pss->len); - lws_callback_on_writable(wsi); - break; + if (pss->buffer != (char *) index_html) free(pss->buffer); + goto try_to_reuse; case LWS_CALLBACK_HTTP_FILE_COMPLETION: goto try_to_reuse; diff --git a/src/index.html b/src/index.html index 2d3d9bf..a530e2a 100644 --- a/src/index.html +++ b/src/index.html @@ -1 +1 @@ -ttyd - Terminal \ No newline at end of file +ttyd - Terminal \ No newline at end of file -- 2.43.4