diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index 5b1be9b61..d572b0b90 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -88,6 +88,7 @@ #cmakedefine LWS_WITH_ESP32 #cmakedefine LWS_WITH_FTS #cmakedefine LWS_WITH_GENCRYPTO +#cmakedefine LWS_WITH_GENERIC_SESSIONS #cmakedefine LWS_WITH_HTTP2 #cmakedefine LWS_WITH_HTTP_BROTLI #cmakedefine LWS_WITH_HTTP_PROXY diff --git a/include/libwebsockets/lws-plugin-generic-sessions.h b/include/libwebsockets/lws-plugin-generic-sessions.h index 7f46f854e..caf27b741 100644 --- a/include/libwebsockets/lws-plugin-generic-sessions.h +++ b/include/libwebsockets/lws-plugin-generic-sessions.h @@ -36,9 +36,9 @@ /* SHA-1 binary and hexified versions */ /** typedef struct lwsgw_hash_bin */ -typedef struct { unsigned char bin[20]; /**< binary representation of hash */} lwsgw_hash_bin; +typedef struct { unsigned char bin[32]; /**< binary representation of hash */} lwsgw_hash_bin; /** typedef struct lwsgw_hash */ -typedef struct { char id[41]; /**< ascii hex representation of hash */ } lwsgw_hash; +typedef struct { char id[65]; /**< ascii hex representation of hash */ } lwsgw_hash; /** enum lwsgs_auth_bits */ enum lwsgs_auth_bits { diff --git a/lib/core-net/connect.c b/lib/core-net/connect.c index 90137119f..9ce91eb5f 100644 --- a/lib/core-net/connect.c +++ b/lib/core-net/connect.c @@ -116,7 +116,12 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i) * we may want ws, but first we have to go through h1 to get that */ - lws_role_call_client_bind(wsi, i); + if (lws_role_call_client_bind(wsi, i) < 0) { + lwsl_err("%s: unable to bind to role\n", __func__); + + goto bail; + } + lwsl_info("%s: role binding to %s\n", __func__, wsi->role_ops->name); /* * PHASE 4: fill up the wsi with stuff from the connect_info as far as @@ -263,6 +268,15 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i) if (i->pwsi) *i->pwsi = wsi; + /* PHASE 8: notify protocol with role-specific connected callback */ + + lwsl_debug("%s: wsi %p: cb %d to %s %s\n", __func__, + wsi, wsi->role_ops->adoption_cb[0], + wsi->role_ops->name, wsi->protocol->name); + + wsi->protocol->callback(wsi, + wsi->role_ops->adoption_cb[0], + wsi->user_space, NULL, 0); #if defined(LWS_WITH_HUBBUB) if (i->uri_replace_to) diff --git a/lib/core-net/dummy-callback.c b/lib/core-net/dummy-callback.c index 010fbb010..697e644f7 100644 --- a/lib/core-net/dummy-callback.c +++ b/lib/core-net/dummy-callback.c @@ -117,6 +117,8 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason, #endif break; + case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: + return 1; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: case LWS_CALLBACK_CLIENT_CLOSED: @@ -132,10 +134,22 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason, proxy_header(wsi, wsi->parent, tmp, sizeof(tmp), WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, p, end); + + proxy_header(wsi, wsi->parent, tmp, sizeof(tmp), + WSI_TOKEN_HTTP_COOKIE, p, end); + + proxy_header(wsi, wsi->parent, tmp, sizeof(tmp), + WSI_TOKEN_HTTP_SET_COOKIE, p, end); break; } case LWS_CALLBACK_CLIENT_RECEIVE: + wsi->parent->ws->proxy_buffered += len; + if (wsi->parent->ws->proxy_buffered > 10 * 1024 * 1024) { + lwsl_err("%s: proxied ws connection excessive buffering: dropping\n", + __func__); + return -1; + } pkt = lws_malloc(sizeof(*pkt) + LWS_PRE + len, __func__); if (!pkt) return -1; @@ -164,6 +178,8 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason, pkt->first, pkt->final)) < 0) return -1; + wsi->parent->ws->proxy_buffered -= pkt->len; + lws_dll_remove_track_tail(dll, &wsi->ws->proxy_head); lws_free(pkt); @@ -173,6 +189,9 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason, /* h1 ws proxying... parent / server / incoming */ + case LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: + return 1; + case LWS_CALLBACK_CLOSED: lwsl_user("%s: closed\n", __func__); return -1; @@ -331,12 +350,15 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY_HEADERS; - lwsl_debug("%s: %p: issuing proxy headers\n", - __func__, wsi); + n = LWS_WRITE_HTTP_HEADERS; + if (!wsi->http.prh_content_length) + n |= LWS_WRITE_H2_STREAM_END; + + lwsl_debug("%s: %p: issuing proxy headers: clen %d\n", + __func__, wsi, (int)wsi->http.prh_content_length); n = lws_write(wsi, wsi->http.pending_return_headers + LWS_PRE, - wsi->http.pending_return_headers_len, - LWS_WRITE_HTTP_HEADERS); + wsi->http.pending_return_headers_len, n); lws_free_set_NULL(wsi->http.pending_return_headers); @@ -468,17 +490,21 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, */ proxy_header(parent, wsi, end, 256, - WSI_TOKEN_HTTP_CONTENT_LENGTH, &p, end); + WSI_TOKEN_HTTP_CONTENT_LENGTH, &p, end); proxy_header(parent, wsi, end, 256, - WSI_TOKEN_HTTP_CONTENT_TYPE, &p, end); + WSI_TOKEN_HTTP_CONTENT_TYPE, &p, end); proxy_header(parent, wsi, end, 256, - WSI_TOKEN_HTTP_ETAG, &p, end); + WSI_TOKEN_HTTP_ETAG, &p, end); proxy_header(parent, wsi, end, 256, - WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, &p, end); + WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, &p, end); proxy_header(parent, wsi, end, 256, - WSI_TOKEN_HTTP_CONTENT_ENCODING, &p, end); + WSI_TOKEN_HTTP_CONTENT_ENCODING, &p, end); proxy_header(parent, wsi, end, 256, - WSI_TOKEN_HTTP_CACHE_CONTROL, &p, end); + WSI_TOKEN_HTTP_CACHE_CONTROL, &p, end); + proxy_header(parent, wsi, end, 256, + WSI_TOKEN_HTTP_SET_COOKIE, &p, end); + proxy_header(parent, wsi, end, 256, + WSI_TOKEN_HTTP_LOCATION, &p, end); if (!parent->http2_substream) if (lws_add_http_header_by_token(parent, @@ -508,8 +534,13 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, if (lws_finalize_http_header(parent, &p, end)) return 1; - parent->http.pending_return_headers_len = - lws_ptr_diff(p, start); + parent->http.prh_content_length = -1; + if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) + parent->http.prh_content_length = atoll( + lws_hdr_simple_ptr(wsi, + WSI_TOKEN_HTTP_CONTENT_LENGTH)); + + parent->http.pending_return_headers_len = lws_ptr_diff(p, start); parent->http.pending_return_headers = lws_malloc(parent->http.pending_return_headers_len + LWS_PRE, "return proxy headers"); @@ -522,7 +553,9 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, parent->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY_HEADERS; lwsl_debug("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: " - "prepared headers\n", __func__); + "prepared %d headers (len %d)\n", __func__, + lws_http_client_http_response(wsi), + (int)parent->http.prh_content_length); /* * so at this point, the onward client connection can bear @@ -565,8 +598,6 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, * connection's request */ - proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), - WSI_TOKEN_HOST, p, end); proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), WSI_TOKEN_HTTP_ETAG, p, end); proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), @@ -577,6 +608,8 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, WSI_TOKEN_HTTP_ACCEPT_ENCODING, p, end); proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), WSI_TOKEN_HTTP_CACHE_CONTROL, p, end); + proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), + WSI_TOKEN_HTTP_COOKIE, p, end); buf[0] = '\0'; lws_get_peer_simple(parent, buf, sizeof(buf)); diff --git a/lib/core/context.c b/lib/core/context.c index 3ae596419..a8479d192 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -89,6 +89,16 @@ lws_create_context(const struct lws_context_creation_info *info) lwsl_err("No memory for websocket context\n"); return NULL; } + + context->uid = info->uid; + context->gid = info->gid; + context->username = info->username; + context->groupname = info->groupname; + + /* if he gave us names, set the uid / gid */ + if (lws_plat_drop_app_privileges(context, 0)) + goto bail; + lwsl_info("context created\n"); #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK) #if defined(LWS_WITH_MBEDTLS) @@ -424,15 +434,6 @@ lwsl_info("context created\n"); lws_server_get_canonical_hostname(context, info); #endif - context->uid = info->uid; - context->gid = info->gid; - context->username = info->username; - context->groupname = info->groupname; - - /* if he gave us names, set the uid / gid */ - if (lws_plat_drop_app_privileges(context, 0)) - goto bail; - #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) memcpy(context->caps, info->caps, sizeof(context->caps)); context->count_caps = info->count_caps; diff --git a/lib/event-libs/libuv/libuv.c b/lib/event-libs/libuv/libuv.c index 22915b2db..8f59f6b55 100644 --- a/lib/event-libs/libuv/libuv.c +++ b/lib/event-libs/libuv/libuv.c @@ -947,7 +947,7 @@ lws_libuv_closehandle(struct lws *wsi) return; if (wsi->told_event_loop_closed) { - assert(0); + // assert(0); return; } diff --git a/lib/misc/lws-struct-sqlite.c b/lib/misc/lws-struct-sqlite.c index 2ed2a4ef1..e89343e8c 100644 --- a/lib/misc/lws-struct-sqlite.c +++ b/lib/misc/lws-struct-sqlite.c @@ -257,6 +257,9 @@ lws_struct_sq3_open(struct lws_context *context, const char *sqlite3_path, chown(sqlite3_path, uid, gid); chmod(sqlite3_path, 0600); + lwsl_notice("%s: created %s owned by %u:%u mode 0600\n", __func__, + sqlite3_path, (unsigned int)uid, (unsigned int)gid); + sqlite3_extended_result_codes(*pdb, 1); return 0; diff --git a/lib/roles/h1/ops-h1.c b/lib/roles/h1/ops-h1.c index 19860b53d..ad8a0baf1 100644 --- a/lib/roles/h1/ops-h1.c +++ b/lib/roles/h1/ops-h1.c @@ -116,7 +116,7 @@ lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len) case LRS_BODY: http_postbody: - lwsl_notice("%s: http post body: remain %d\n", __func__, + lwsl_debug("%s: http post body: remain %d\n", __func__, (int)wsi->http.rx_content_remain); if (!wsi->http.rx_content_remain) @@ -659,28 +659,36 @@ rops_handle_POLLOUT_h1(struct lws *wsi) if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY) { #if defined(LWS_WITH_HTTP_PROXY) if (wsi->http.proxy_clientside) { - unsigned char *buf; + unsigned char *buf, prebuf[LWS_PRE + 1024]; size_t len = lws_buflist_next_segment_len( &wsi->parent->http.buflist_post_body, &buf); int n; - lwsl_debug("%s: %p: proxying body %d %d %d %d %d\n", - __func__, wsi, (int)len, - (int)wsi->http.tx_content_length, - (int)wsi->http.tx_content_remain, - (int)wsi->http.rx_content_length, - (int)wsi->http.rx_content_remain - ); + if (len) { - n = lws_write(wsi, buf, len, LWS_WRITE_HTTP); - if (n < 0) { - lwsl_err("%s: PROXY_BODY: write failed\n", - __func__); - return -1; + if (len > sizeof(prebuf) - LWS_PRE) + len = sizeof(prebuf) - LWS_PRE; + + memcpy(prebuf + LWS_PRE, buf, len); + + lwsl_debug("%s: %p: proxying body %d %d %d %d %d\n", + __func__, wsi, (int)len, + (int)wsi->http.tx_content_length, + (int)wsi->http.tx_content_remain, + (int)wsi->http.rx_content_length, + (int)wsi->http.rx_content_remain + ); + + n = lws_write(wsi, prebuf + LWS_PRE, len, LWS_WRITE_HTTP); + if (n < 0) { + lwsl_err("%s: PROXY_BODY: write %d failed\n", + __func__, (int)len); + return LWS_HP_RET_BAIL_DIE; + } + + lws_buflist_use_segment(&wsi->parent->http.buflist_post_body, len); } - lws_buflist_use_segment(&wsi->parent->http.buflist_post_body, len); - if (wsi->parent->http.buflist_post_body) lws_callback_on_writable(wsi); else { diff --git a/lib/roles/http/private.h b/lib/roles/http/private.h index 9c275f9f7..a81a24e77 100644 --- a/lib/roles/http/private.h +++ b/lib/roles/http/private.h @@ -212,6 +212,7 @@ struct _lws_http_mode_related { unsigned char *pending_return_headers; size_t pending_return_headers_len; + size_t prh_content_length; #if defined(LWS_WITH_HTTP_PROXY) struct lws_rewrite *rw; diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index 29439f42a..434648521 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -672,6 +672,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin, lwsl_debug("sending no mimetype for %s\n", path); wsi->sending_chunked = 0; + wsi->interpreting = 0; /* * check if this is in the list of file suffixes to be interpreted by @@ -684,13 +685,20 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin, wsi->interpreting = 1; if (!wsi->http2_substream) wsi->sending_chunked = 1; + wsi->protocol_interpret_idx = - (char)(lws_intptr_t)pvo->value; - lwsl_info("want %s interpreted by %s\n", path, + lws_vhost_name_to_protocol(wsi->vhost, + pvo->value) - + &lws_get_vhost(wsi)->protocols[0]; + + lwsl_debug("want %s interpreted by %s (pcol is %s)\n", path, wsi->vhost->protocols[ - (int)(lws_intptr_t)(pvo->value)].name); - wsi->protocol = &wsi->vhost->protocols[ - (int)(lws_intptr_t)(pvo->value)]; + (int)wsi->protocol_interpret_idx].name, + wsi->protocol->name); + if (lws_bind_protocol(wsi, &wsi->vhost->protocols[ + (int)wsi->protocol_interpret_idx], __func__)) + return -1; + if (lws_ensure_user_space(wsi)) return -1; break; @@ -698,6 +706,14 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin, pvo = pvo->next; } + if (wsi->sending_chunked) { + if (lws_add_http_header_by_token(wsi, + WSI_TOKEN_HTTP_TRANSFER_ENCODING, + (unsigned char *)"chunked", 7, + &p, end)) + return -1; + } + if (m->protocol) { const struct lws_protocols *pp = lws_vhost_name_to_protocol( wsi->vhost, m->protocol); @@ -1091,11 +1107,29 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit, } i.path = rpath; + + /* incoming may be h1 or h2... if he sends h1 HOST, use that + * directly, otherwise we must convert h2 :authority to h1 + * host */ + + i.host = NULL; + n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY); + if (n > 0) + i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY); + else { + n = lws_hdr_total_length(wsi, WSI_TOKEN_HOST); + if (n > 0) { + i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST); + } + } + +#if 0 if (i.address[0] != '+' || !lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)) i.host = i.address; else i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST); +#endif i.origin = NULL; if (!ws) { if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI) @@ -1111,7 +1145,12 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit, i.method = "GET"; } - lws_snprintf(host, sizeof(host), "%s:%d", i.address, i.port); + if (i.host) + lws_snprintf(host, sizeof(host), "%s:%u", i.host, + wsi->vhost->listen_port); + else + lws_snprintf(host, sizeof(host), "%s:%d", i.address, i.port); + i.host = host; i.alpn = "http/1.1"; @@ -1423,7 +1462,7 @@ lws_http_action(struct lws *wsi) if (hit->origin_protocol == LWSMPRO_HTTPS || hit->origin_protocol == LWSMPRO_HTTP) { n = lws_http_proxy_start(wsi, hit, uri_ptr, 0); - lwsl_notice("proxy start says %d\n", n); + // lwsl_notice("proxy start says %d\n", n); if (n) return n; @@ -1454,6 +1493,9 @@ lws_http_action(struct lws *wsi) if (lws_bind_protocol(wsi, pp, "http action CALLBACK bind")) return 1; + lwsl_notice("%s: %s, checking access rights for mask 0x%x\n", + __func__, hit->origin, hit->auth_mask); + args.p = uri_ptr; args.len = uri_len; args.max_len = hit->auth_mask; @@ -1569,7 +1611,7 @@ deal_body: */ if (lwsi_state(wsi) != LRS_ISSUING_FILE) { /* Prepare to read body if we have a content length: */ - lwsl_notice("wsi->http.rx_content_length %lld %d %d\n", + lwsl_debug("wsi->http.rx_content_length %lld %d %d\n", (long long)wsi->http.rx_content_length, wsi->upgraded_to_http2, wsi->http2_substream); @@ -2297,9 +2339,10 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type, * method that the client said he will accept */ - if (!strncmp(content_type, "text/", 5) || - !strcmp(content_type, "application/javascript") || - !strcmp(content_type, "image/svg+xml")) + if (!wsi->interpreting && ( + !strncmp(content_type, "text/", 5) || + !strcmp(content_type, "application/javascript") || + !strcmp(content_type, "image/svg+xml"))) lws_http_compression_apply(wsi, NULL, &p, end, 0); } #endif @@ -2827,7 +2870,7 @@ skip: s->swallow[s->pos] = '\0'; if (n != s->pos) { memmove(s->start + n, s->start + s->pos, - old_len - (sp - args->p)); + old_len - (sp - args->p) - 1); old_len += (n - s->pos) + 1; } memcpy(s->start, pc, n); diff --git a/lib/roles/ws/ext/extension-permessage-deflate.c b/lib/roles/ws/ext/extension-permessage-deflate.c index 1c01d93da..820a108f2 100644 --- a/lib/roles/ws/ext/extension-permessage-deflate.c +++ b/lib/roles/ws/ext/extension-permessage-deflate.c @@ -358,9 +358,8 @@ lws_extension_callback_pm_deflate(struct lws_context *context, __func__, pmdrx->eb_out.len, priv->rx.avail_in, (unsigned long)priv->count_rx_between_fin); - if (was_fin) { + if (was_fin && !pen) { lwsl_ext("%s: was_fin\n", __func__); - assert(!pen); priv->count_rx_between_fin = 0; if (priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER]) { lwsl_ext("PMD_SERVER_NO_CONTEXT_TAKEOVER\n"); diff --git a/lib/roles/ws/private.h b/lib/roles/ws/private.h index ad86708bc..290bf42f6 100644 --- a/lib/roles/ws/private.h +++ b/lib/roles/ws/private.h @@ -96,6 +96,7 @@ struct _lws_websocket_related { #if defined(LWS_WITH_HTTP_PROXY) struct lws_dll proxy_head; char actual_protocol[16]; + size_t proxy_buffered; #endif /* Also used for close content... control opcode == < 128 */ diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-generic-sessions/CMakeLists.txt new file mode 100644 index 000000000..dc9b0f499 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/CMakeLists.txt @@ -0,0 +1,82 @@ +cmake_minimum_required(VERSION 2.8) +include(CheckCSourceCompiles) + +set(SAMP lws-minimal-http-server-generic-sessions) +set(SRCS minimal-http-server-generic-sessions.c) + +# If we are being built as part of lws, confirm current build config supports +# reqconfig, else skip building ourselves. +# +# If we are being built externally, confirm installed lws was configured to +# support reqconfig, else error out with a helpful message about the problem. +# +MACRO(require_lws_config reqconfig _val result) + + if (DEFINED ${reqconfig}) + if (${reqconfig}) + set (rq 1) + else() + set (rq 0) + endif() + else() + set(rq 0) + endif() + + if (${_val} EQUAL ${rq}) + set(SAME 1) + else() + set(SAME 0) + endif() + + if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME}) + if (${_val}) + message("${SAMP}: skipping as lws being built without ${reqconfig}") + else() + message("${SAMP}: skipping as lws built with ${reqconfig}") + endif() + set(${result} 0) + else() + if (LWS_WITH_MINIMAL_EXAMPLES) + set(MET ${SAME}) + else() + CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig}) + if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig}) + set(HAS_${reqconfig} 0) + else() + set(HAS_${reqconfig} 1) + endif() + if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val})) + set(MET 1) + else() + set(MET 0) + endif() + endif() + if (NOT MET) + if (${_val}) + message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}") + else() + message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project") + endif() + endif() + + endif() +ENDMACRO() + +set(requirements 1) +require_lws_config(LWS_ROLE_H1 1 requirements) +require_lws_config(LWS_WITHOUT_SERVER 0 requirements) +require_lws_config(LWS_OPENSSL_SUPPORT 1 requirements) +require_lws_config(LWS_WITH_GENERIC_SESSIONS 1 requirements) +require_lws_config(LWS_WITH_LIBUV 1 requirements) +require_lws_config(LWS_WITH_PLUGINS 1 requirements) + +if (requirements) + add_executable(${SAMP} ${SRCS}) + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets) + endif() +endif() diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/README.md b/minimal-examples/http-server/minimal-http-server-generic-sessions/README.md new file mode 100644 index 000000000..976aea686 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/README.md @@ -0,0 +1,26 @@ +# lws minimal http server with generic-sessions + +## build + +``` + $ cmake . && make +``` + +## usage + +``` + $ ./lws-minimal-http-server-tls +[2018/03/20 13:23:13:0131] USER: LWS minimal http server TLS | visit https://localhost:7681 +[2018/03/20 13:23:13:0142] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 off +[2018/03/20 13:23:13:0142] NOTICE: Using SSL mode +[2018/03/20 13:23:13:0146] NOTICE: SSL ECDH curve 'prime256v1' +[2018/03/20 13:23:13:0146] NOTICE: HTTP2 / ALPN enabled +[2018/03/20 13:23:13:0195] NOTICE: lws_tls_client_create_vhost_context: doing cert filepath localhost-100y.cert +[2018/03/20 13:23:13:0195] NOTICE: Loaded client cert localhost-100y.cert +[2018/03/20 13:23:13:0195] NOTICE: lws_tls_client_create_vhost_context: doing private key filepath +[2018/03/20 13:23:13:0196] NOTICE: Loaded client cert private key localhost-100y.key +[2018/03/20 13:23:13:0196] NOTICE: created client ssl context for default +[2018/03/20 13:23:14:0207] NOTICE: vhost default: cert expiry: 730459d +``` + + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/localhost-100y.cert b/minimal-examples/http-server/minimal-http-server-generic-sessions/localhost-100y.cert new file mode 100644 index 000000000..6f372db40 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/localhost-100y.cert @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF5jCCA86gAwIBAgIJANq50IuwPFKgMA0GCSqGSIb3DQEBCwUAMIGGMQswCQYD +VQQGEwJHQjEQMA4GA1UECAwHRXJld2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEb +MBkGA1UECgwSbGlid2Vic29ja2V0cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3Qx +HzAdBgkqhkiG9w0BCQEWEG5vbmVAaW52YWxpZC5vcmcwIBcNMTgwMzIwMDQxNjA3 +WhgPMjExODAyMjQwNDE2MDdaMIGGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRXJl +d2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEbMBkGA1UECgwSbGlid2Vic29ja2V0 +cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEG5vbmVA +aW52YWxpZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCjYtuW +aICCY0tJPubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8 +Di3DAmHKnSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTek +LWcfI5ZZtoGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnH +KT/m6DSU0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6 +jzhNyMBTJ1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQ +Ujy5N8pSNp7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAz +TK4l2pHNuC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBK +Izv9cgi9fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0 +nPN1IMSnzXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzo +GMTvP/AuehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9p +sNcjTMaBQLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABo1MwUTAdBgNVHQ4EFgQU +9mYU23tW2zsomkKTAXarjr2vjuswHwYDVR0jBBgwFoAU9mYU23tW2zsomkKTAXar +jr2vjuswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEANjIBMrow +YNCbhAJdP7dhlhT2RUFRdeRUJD0IxrH/hkvb6myHHnK8nOYezFPjUlmRKUgNEDuA +xbnXZzPdCRNV9V2mShbXvCyiDY7WCQE2Bn44z26O0uWVk+7DNNLH9BnkwUtOnM9P +wtmD9phWexm4q2GnTsiL6Ul6cy0QlTJWKVLEUQQ6yda582e23J1AXqtqFcpfoE34 +H3afEiGy882b+ZBiwkeV+oq6XVF8sFyr9zYrv9CvWTYlkpTQfLTZSsgPdEHYVcjv +xQ2D+XyDR0aRLRlvxUa9dHGFHLICG34Juq5Ai6lM1EsoD8HSsJpMcmrH7MWw2cKk +ujC3rMdFTtte83wF1uuF4FjUC72+SmcQN7A386BC/nk2TTsJawTDzqwOu/VdZv2g +1WpTHlumlClZeP+G/jkSyDwqNnTu1aodDmUa4xZodfhP1HWPwUKFcq8oQr148QYA +AOlbUOJQU7QwRWd1VbnwhDtQWXC92A2w1n/xkZSR1BM/NUSDhkBSUU1WjMbWg6Gg +mnIZLRerQCu1Oozr87rOQqQakPkyt8BUSNK3K42j2qcfhAONdRl8Hq8Qs5pupy+s +8sdCGDlwR3JNCMv6u48OK87F4mcIxhkSefFJUFII25pCGN5WtE4p5l+9cnO1GrIX +e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE= +-----END CERTIFICATE----- diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/localhost-100y.key b/minimal-examples/http-server/minimal-http-server-generic-sessions/localhost-100y.key new file mode 100644 index 000000000..148f8598e --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/localhost-100y.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +fBrpEY1IATtPq1taBZZogRqI3rOkkPk= +-----END PRIVATE KEY----- diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/minimal-http-server-generic-sessions.c b/minimal-examples/http-server/minimal-http-server-generic-sessions/minimal-http-server-generic-sessions.c new file mode 100644 index 000000000..753dc6318 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/minimal-http-server-generic-sessions.c @@ -0,0 +1,202 @@ +/* + * lws-minimal-http-server-generic-sessions + * + * Copyright (C) 2019 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * This demonstrates setting up and using generic sessions + */ + +#include +#include +#include + +static int interrupted; +struct lws_context *context; + +static const struct lws_protocol_vhost_options + pvo_mm1 = { + NULL, NULL, "message-db", (void *)"/var/www/sessions/messageboard.sqlite3" +}, pvo_m1 = { + NULL, &pvo_mm1, "protocol-lws-messageboard", "" +}, + + pvo13 = { + NULL, NULL, "email-confirm-url-base", (void *)"https://localhost:7681/" +}, pvo12 = { + &pvo13, NULL, "urlroot", (void *)"https://127.0.0.1:7681/" +}, pvo11 = { + &pvo12, NULL, "email-contact-person", (void *)"andy@warmcat.com" +}, pvo10 = { + &pvo11, NULL, "email-helo", (void *)"warmcat.com" +}, pvo9 = { + &pvo10, NULL, "email-expire", (void *)"3600" +}, pvo8 = { + &pvo9, NULL, "email-smtp-ip", (void *)"127.0.0.1" +}, pvo7 = { + &pvo8, NULL, "email-from", (void *)"noreply@warmcat.com" +}, pvo6 = { + &pvo7, NULL, "confounder", (void *)"some kind of secret confounder" +}, pvo5 = { + &pvo6, NULL, "timeout-anon-idle-secs", (void *)"1200" +}, pvo4 = { + &pvo5, NULL, "timeout-idle-secs", (void *)"6000" +}, pvo3 = { + &pvo4, NULL, "session-db", (void *)"/var/www/sessions/lws.sqlite3" +}, pvo2 = { + &pvo3, NULL, "admin-password-sha256", + (void *)"25d08521d996bad92605f5a40fe71179dc968e70f669cb1db6190dcd53258200" /* pvo value */ +}, pvo1 = { + &pvo2, NULL, "admin-user", (void *)"admin" +}, pvo = { + &pvo_m1, &pvo1, "protocol-generic-sessions", "" +}, + + interpret1 = { + NULL, NULL, ".js", "protocol-lws-messageboard" +}, + + pvo_hsbph[] = {{ + NULL, NULL, "referrer-policy:", "no-referrer" +}, { + &pvo_hsbph[0], NULL, "x-xss-protection:", "1; mode=block" +}, { + &pvo_hsbph[1], NULL, "x-content-type-options:", "nosniff" +}, { + &pvo_hsbph[2], NULL, "content-security-policy:", + "default-src 'self'; " + "img-src https://www.gravatar.com 'self' data: ; " + "script-src 'self'; " + "font-src 'self'; " + "style-src 'self'; " + "connect-src 'self'; " + "frame-ancestors 'self'; " + "base-uri 'none'; " + "form-action 'self';" +}}; + + static const struct lws_http_mount mount2 = { + /* .mount_next */ NULL, /* linked-list "next" */ + /* .mountpoint */ "/needadmin", /* mountpoint URL */ + /* .origin */ "./mount-origin/needadmin", /* serve from dir */ + /* .def */ "index.html", /* default filename */ + /* .protocol */ "protocol-lws-messageboard", + /* .cgienv */ NULL, + /* .extra_mimetypes */ NULL, + /* .interpret */ &interpret1, + /* .cgi_timeout */ 0, + /* .cache_max_age */ 0, + /* .auth_mask */ 7, + /* .cache_reusable */ 0, + /* .cache_revalidate */ 0, + /* .cache_intermediaries */ 0, + /* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */ + /* .mountpoint_len */ 1, /* char count */ + /* .basic_auth_login_file */ NULL, + }; + + static const struct lws_http_mount mount1 = { + /* .mount_next */ &mount2, /* linked-list "next" */ + /* .mountpoint */ "/needauth", /* mountpoint URL */ + /* .origin */ "./mount-origin/needauth", /* serve from dir */ + /* .def */ "index.html", /* default filename */ + /* .protocol */ "protocol-lws-messageboard", + /* .cgienv */ NULL, + /* .extra_mimetypes */ NULL, + /* .interpret */ &interpret1, + /* .cgi_timeout */ 0, + /* .cache_max_age */ 0, + /* .auth_mask */ 5, + /* .cache_reusable */ 0, + /* .cache_revalidate */ 0, + /* .cache_intermediaries */ 0, + /* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */ + /* .mountpoint_len */ 1, /* char count */ + /* .basic_auth_login_file */ NULL, + }; + +static const struct lws_http_mount mount = { + /* .mount_next */ &mount1, /* linked-list "next" */ + /* .mountpoint */ "/", /* mountpoint URL */ + /* .origin */ "./mount-origin", /* serve from dir */ + /* .def */ "index.html", /* default filename */ + /* .protocol */ "protocol-lws-messageboard", + /* .cgienv */ NULL, + /* .extra_mimetypes */ NULL, + /* .interpret */ &interpret1, + /* .cgi_timeout */ 0, + /* .cache_max_age */ 0, + /* .auth_mask */ 0, + /* .cache_reusable */ 0, + /* .cache_revalidate */ 0, + /* .cache_intermediaries */ 0, + /* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */ + /* .mountpoint_len */ 1, /* char count */ + /* .basic_auth_login_file */ NULL, +}; + +void sigint_handler(int sig) +{ + lws_context_destroy(context); + + interrupted = 1; +} + +int main(int argc, const char **argv) +{ + struct lws_context_creation_info info; + const char *p, *plugin_dirs[] = { + "/usr/local/share/libwebsockets-test-server/plugins", + NULL }; + int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE + /* for LLL_ verbosity above NOTICE to be built into lws, + * lws must have been configured and built with + * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ + /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ + /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ + /* | LLL_DEBUG */; + + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS minimal http server TLS | visit https://localhost:7681\n"); + + signal(SIGINT, sigint_handler); + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = 7681; + info.mounts = &mount; + info.error_document_404 = "/404.html"; + info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | + LWS_SERVER_OPTION_EXPLICIT_VHOSTS; + info.ssl_cert_filepath = "localhost-100y.cert"; + info.ssl_private_key_filepath = "localhost-100y.key"; + info.plugin_dirs = plugin_dirs; + info.pvo = &pvo; + + if (lws_cmdline_option(argc, argv, "-h")) + info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK; + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + info.headers = &pvo_hsbph[3]; + + if (!lws_create_vhost(context, &info)) { + lwsl_err("lws init failed\n"); + return 1; + } + + while (n >= 0 && !interrupted) + n = lws_service(context, 1000); + + lws_context_destroy(context); + + return 0; +} diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/404.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/404.html new file mode 100644 index 000000000..6fdd6bf33 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/404.html @@ -0,0 +1,11 @@ + + + + +
+ +

404

+ Sorry, that file doesn't exist. + + + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/admin-login.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/admin-login.html new file mode 100644 index 000000000..113df9cd3 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/admin-login.html @@ -0,0 +1,5 @@ + +This is an example destination that will appear after successful Admin login. + +This URL cannot be served if you're not logged in as admin. + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/example.js b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/example.js new file mode 100644 index 000000000..1606ea03a --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/example.js @@ -0,0 +1,22 @@ +document.addEventListener("DOMContentLoaded", function() { + + var transport_protocol = ""; + + if ( performance && performance.timing.nextHopProtocol ) { + transport_protocol = performance.timing.nextHopProtocol; + } else if ( window.chrome && window.chrome.loadTimes ) { + transport_protocol = window.chrome.loadTimes().connectionInfo; + } else { + + var p = performance.getEntriesByType("resource"); + for (var i=0; i < p.length; i++) { + var value = "nextHopProtocol" in p[i]; + if (value) + transport_protocol = p[i].nextHopProtocol; + } + } + + if (transport_protocol == "h2") + document.getElementById("transport").innerHTML = ""; + } +}, false); \ No newline at end of file diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/failed-login.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/failed-login.html new file mode 100644 index 000000000..9ab065b53 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/failed-login.html @@ -0,0 +1,3 @@ + +This is an example destination that will appear after a failed login + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/favicon.ico b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/favicon.ico new file mode 100644 index 000000000..c0cc2e3df Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/favicon.ico differ diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/http2.png b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/http2.png new file mode 100644 index 000000000..439bfa482 Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/http2.png differ diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/index.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/index.html new file mode 100644 index 000000000..0695d5d3a --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/index.html @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + +
+
+
+ +
+ + This is a demo application for lws generic-sessions.

+ It's a simple messageboard.

+ What's interesting about it is there is no serverside scripting,
+ instead client js makes a wss:// connection back to the server
+ and then reacts to JSON from the ws protocol. Sessions stuff is
+ handled by lws generic sessions, making the actual
+ test application
very small.

+ And because it's natively websocket, it's naturally connected
+ for dynamic events and easy to maintain. +

+ Register / Login at the top right to see and create new messages. +
+ +
+
+ New message
+
+ +
+
+
+
+ +
+ +
+
+ + + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/libwebsockets.org-logo.svg b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/libwebsockets.org-logo.svg new file mode 100644 index 000000000..7baea649f --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/libwebsockets.org-logo.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lws-common.js b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lws-common.js new file mode 100644 index 000000000..5d56ca2dc --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lws-common.js @@ -0,0 +1,128 @@ +/* + * This section around grayOut came from here: + * http://www.codingforums.com/archive/index.php/t-151720.html + * Assumed public domain + * + * Init like this in your main html script, this also reapplies the gray + * + * lws_gray_out(true,{'zindex':'499'}); + * + * To remove the gray + * + * lws_gray_out(false); + * + */ + +function gsize(ptype) +{ + var h = document.compatMode === "CSS1Compat" && + !window.opera ? + document.documentElement.clientHeight : + document.body.clientHeight; + var w = document.compatMode === "CSS1Compat" && + !window.opera ? + document.documentElement.clientWidth : + document.body.clientWidth; + var pageWidth, pageHeight, t; + + if (document.body && + (document.body.scrollWidth || document.body.scrollHeight)) { + t = document.body.scrollWidth; + pageWidth = (w > t) ? ("" + w + "px") : ("" + (t) + "px"); + t = document.body.scrollHeight; + pageHeight = (h > t) ? ("" + h + "px") : ("" + (t) + "px"); + } else if (document.body.offsetWidth) { + t = document.body.offsetWidth; + pageWidth = (w > t) ? ("" + w + "px") : ("" + (t) + "px"); + t = document.body.offsetHeight; + pageHeight =(h > t) ? ("" + h + "px") : ("" + (t) + "px"); + } else { + pageWidth = "100%"; + pageHeight = "100%"; + } + return (ptype === 1) ? pageWidth : pageHeight; +} + +function addEvent( obj, type, fn ) { + if ( obj.attachEvent ) { + obj["e" + type + fn] = fn; + obj[type+fn] = function() { obj["e" + type + fn]( window.event );}; + obj.attachEvent("on" + type, obj[type + fn]); + } else + obj.addEventListener(type, fn, false); +} + +function removeEvent( obj, type, fn ) { + if ( obj.detachEvent ) { + obj.detachEvent("on" + type, obj[type + fn]); + obj[type + fn] = null; + } else + obj.removeEventListener(type, fn, false); +} + +function lws_gray_out(vis, _options) { + + var options = _options || {}; + var zindex = options.zindex || 50; + var opacity = options.opacity || 70; + var opaque = (opacity / 100); + var bgcolor = options.bgcolor || "#000000"; + var dark = document.getElementById("darkenScreenObject"); + + if (!dark) { + var tbody = document.getElementsByTagName("body")[0]; + var tnode = document.createElement("div"); + tnode.style.position = "absolute"; + tnode.style.top = "0px"; + tnode.style.left = "0px"; + tnode.style.overflow = "hidden"; + tnode.style.display ="none"; + tnode.id = "darkenScreenObject"; + tbody.appendChild(tnode); + dark = document.getElementById("darkenScreenObject"); + } + if (vis) { + dark.style.opacity = opaque; + dark.style.MozOpacity = opaque; + // dark.style.filter ='alpha(opacity='+opacity+')'; + dark.style.zIndex = zindex; + dark.style.backgroundColor = bgcolor; + dark.style.width = gsize(1); + dark.style.height = gsize(0); + dark.style.display = "block"; + addEvent(window, "resize", + function() { + dark.style.height = gsize(0); + dark.style.width = gsize(1); + } + ); + } else { + dark.style.display = "none"; + removeEvent(window, "resize", + function() { + dark.style.height = gsize(0); + dark.style.width = gsize(1); + } + ); + } +} + +/* + * end of grayOut related stuff + */ + +function new_ws(urlpath, protocol) +{ + if (typeof MozWebSocket != "undefined") + return new MozWebSocket(urlpath, protocol); + + return new WebSocket(urlpath, protocol); +} + +function lws_san(s) +{ + if (s.search("<") !== -1) + return "invalid string"; + + return s; +} diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs-logo.png b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs-logo.png new file mode 100644 index 000000000..723a12443 Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs-logo.png differ diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.css b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.css new file mode 100644 index 000000000..907851f0e --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.css @@ -0,0 +1,144 @@ +.body { font-size: 12px } +.gstitle { font-size: 18px } + +.group1 { + vertical-align:middle; + text-align:center; + background:#f0f0e0; + padding:12px; + border-radius:10px; +} +.group2 { + display:block; + vertical-align:middle; + font-size: 22px; + text-align:center; + margin:auto; + align:center; + background-color: rgba(255, 255, 255, 0.8); + padding:12px; + border-radius:10px; +} + +body { + background-color: rgba(205, 205, 205, 1); +} + +div.lwsgs { + z-index: 3; + text-align:right; + background-color: rgba(255, 255, 255, 0.8); +} + +table.lwsgs { + width:100%; + height:100%; + transition: max-height 2s; +} +table.c100 { + text-align:center; + width:100%; +} + +table.r { + vertical-align:top; + text-align:right; +} + +table.l { + vertical-align:top; + text-align:left; +} + +table.fixed { + table-layout: fixed; +} + +td.logo { + vertical-align:top; + text-align:left; + width:200px +} + +td.rlogo { + vertical-align:top; + text-align:right +} + +td.lwsgs { + vertical-align:top; + float:right; +} + +td.h99 { + height:99%; + vertical-align:middle; +} + +td.c { + margin:auto; + align:center +} + +td.tac { + text-align:center +} + +td.ava { + display:inline-block; + vertical-align:top; + word-wrap:break-word; +} + +iframe.hidden { + display:none; +} + +div.hidden { + display:none; +} + +div.hiddenr { + display:none; + text-align:right; +} + +input { + margin: 2px; + padding: 2px; +} + +input.em { + margin: 4px; + font-weight:bold; +} + +input.wide { + margin: 6px; + padding: 6px; +} + +input.hidden { + display: none; +} + +form.r { + text-align:right; +} + +span.bad { + color: red; +} + +span.small { + font-size:8pt; +} + +img.av { + width: 64px; + height: 64px; +} + +.green { + color: green; +} diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.js b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.js new file mode 100644 index 000000000..059ad118c --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.js @@ -0,0 +1,637 @@ + + +var lwsgs_user = "$lwsgs_user"; +var lwsgs_auth = "$lwsgs_auth"; +var lwsgs_email = "$lwsgs_email"; + +var lwsgs_html = '\ + \ +\ +
\ +
\ + \ + \ + \ + \ +
\ + \ +
\ + \ +
\ +\ + \ + \ + \ + \ + \ +'; + +/*-- this came from + -- https://raw.githubusercontent.com/blueimp/JavaScript-MD5/master/js/md5.min.js + -- under MIT license */ +!function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t),e=(n>>16)+(t>>16)+(r>>16);return e<<16|65535&r}function r(n,t){return n<>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<>>9<<4)+14]=r;var e,i,a,h,d,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e>5]>>>t%32&255);return r}function h(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t>5]|=(255&n.charCodeAt(t/8))<16&&(o=i(o,8*n.length)),r=0;16>r;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(h(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="0123456789abcdef",o="";for(r=0;r>>4&15)+e.charAt(15&t);return o}function v(n){return unescape(encodeURIComponent(n))}function m(n){return d(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this); + +if (lwsgs_user.substring(0, 1) == "$") { + alert("lwsgs.js: lws generic sessions misconfigured and not providing vars"); +} +function lwsgs_san(s) +{ + if (s.search("<") != -1) + return "invalid string"; + + return s; +} + +function lwsgs_update() +{ + var en_login = 1, en_forgot = 1; + + if (document.getElementById('password').value.length && + document.getElementById('password').value.length < 8) + en_login = 0; + + if (!document.getElementById('username').value || + !document.getElementById('password').value) + en_login = 0; + + if (!document.getElementById('username').value || + document.getElementById('password').value) + en_forgot = 0; + + document.getElementById('login').disabled = !en_login; + document.getElementById('forgot').disabled = !en_forgot; + + if (lwsgs_user) + document.getElementById("curuser").innerHTML = lwsgs_san(lwsgs_user); + + if (lwsgs_user === "") + document.getElementById("dlogin").style.display = "inline"; + else + document.getElementById("dlogout").style.display = "inline"; + } + +function lwsgs_open_registration() +{ + document.getElementById("dadmin").style.display = "none"; + document.getElementById("dlogin").style.display = "none"; + document.getElementById("dlogout").style.display = "none"; + document.getElementById("dchange").style.display = "none"; + document.getElementById("dregister").style.display = "inline"; +} + +function lwsgs_cancel_registration() +{ + document.getElementById("dadmin").style.display = "none"; + document.getElementById("dregister").style.display = "none"; + document.getElementById("dchange").style.display = "none"; + + if (lwsgs_user === "") + document.getElementById("dlogin").style.display = "inline"; + else + document.getElementById("dlogout").style.display = "inline"; +} + +function lwsgs_select_change() +{ + document.getElementById("dlogin").style.display = "none"; + document.getElementById("dlogout").style.display = "none"; + document.getElementById("dregister").style.display = "none"; + if (lwsgs_auth & 2) { + document.getElementById("dadmin").style.display = "inline"; + document.getElementById("dchange").style.display = "none"; + } else { + document.getElementById("dadmin").style.display = "none"; + document.getElementById("dchange").style.display = "inline"; + } + + event.preventDefault() +} + +var lwsgs_user_check = '0'; +var lwsgs_email_check = '0'; + +function lwsgs_rupdate() +{ + var en_register = 1, en_forgot = 0; + + if (document.getElementById('rpassword').value == + document.getElementById('password2').value) { + if (document.getElementById('rpassword').value.length) + document.getElementById('match').innerHTML = + "\u2713"; + else + document.getElementById('match').innerHTML = ""; + document.getElementById('pw2').style = ""; + } else { + if (document.getElementById('password2').value || + document.getElementById('email').value) { // ie, he is filling in "register" path and cares + document.getElementById('match').innerHTML = + "\u2718 Passwords do not match"; + } else + document.getElementById('match').innerHTML = + "\u2718 Passwords do not match"; + + en_register = 0; + } + + if (document.getElementById('rpassword').value.length && + document.getElementById('rpassword').value.length < 8) { + en_register = 0; + document.getElementById('rpw1').innerHTML = "Need 8 chars"; + } else + if (document.getElementById('rpassword').value.length) + document.getElementById('rpw1').innerHTML = "\u2713"; + else + document.getElementById('rpw1').innerHTML = ""; + + if (!document.getElementById('rpassword').value || + !document.getElementById('password2').value || + !document.getElementById('rusername').value || + !document.getElementById('email').value || + lwsgs_email_check === '1'|| + lwsgs_user_check === '1') + en_register = 0; + + document.getElementById('register').disabled = !en_register; + document.getElementById('rpassword').disabled = lwsgs_user_check === '1'; + document.getElementById('password2').disabled = lwsgs_user_check === '1'; + document.getElementById('email').disabled = lwsgs_user_check === '1'; + + if (lwsgs_user_check === '0') { + var uc = document.getElementById('uchk'); + + if (uc) { + if (document.getElementById('rusername').value) + uc.innerHTML = "\u2713"; + else + uc.innerHTML = ""; + } + } else { + if (document.getElementById('uchk')) + ocument.getElementById('uchk').innerHTML = "\u2718 Already registered"; + en_forgot = 1; + } + + if (lwsgs_email_check === '0') { + var ec = document.getElementById('echk'); + + if (ec) { + if (document.getElementById('email').value) + ec.innerHTML = "\u2713"; + else + ec.innerHTML = ""; + } + } else { + if (document.getElementById('echk')) + document.getElementById('echk').innerHTML = "\u2718 Already registered"; + en_forgot = 1; + } + + if (en_forgot) + document.getElementById('rforgot').style.display = "inline"; + else + document.getElementById('rforgot').style.display = "none"; + + if (lwsgs_user_check === '1') + op = '0.5'; + else + op = '1.0'; + document.getElementById('rpassword').style.opacity = op; + document.getElementById('password2').style.opacity = op; + document.getElementById('email').style.opacity = op; + } + +function lwsgs_cupdate() +{ + var en_change = 1, en_forgot = 1, pwok = 1; + + if (lwsgs_auth & 8) { + document.getElementById('ccurpw').style.display = "none"; + document.getElementById('ccurpw_name').style.display = "none"; + } else { + if (!document.getElementById('ccurpw').value || + document.getElementById('ccurpw').value.length < 8) { + en_change = 0; + pwok = 0; + document.getElementById('cuchk').innerHTML = "\u2718"; + } else { + en_forgot = 0; + document.getElementById('cuchk').innerHTML = ""; + } + document.getElementById('ccurpw').style.display = "inline"; + document.getElementById('ccurpw_name').style.display = "inline"; + } + + if (document.getElementById('cpassword').value == + document.getElementById('cpassword2').value) { + if (document.getElementById('cpassword').value.length) + document.getElementById('cmatch').innerHTML = "\u2713"; + else + document.getElementById('cmatch').innerHTML = ""; + document.getElementById('pw2').style = ""; + } else { + if (document.getElementById('cpassword2').value //|| + //document.getElementById('cemail').value + ) { // ie, he is filling in "register" path and cares + document.getElementById('cmatch').innerHTML = + "\u2718 Passwords do not match"; + } else + document.getElementById('cmatch').innerHTML = "\u2718 Passwords do not match"; + + en_change = 0; + } + + if (document.getElementById('cpassword').value.length && + document.getElementById('cpassword').value.length < 8) { + en_change = 0; + document.getElementById('cpw1').innerHTML = "Need 8 chars"; + } else { + var cpw = document.getElementById('cpw1'); + + if (cpw) { + if (document.getElementById('cpassword').value.length) + cpw.innerHTML = "\u2713"; + else + cpw.innerHTML = ""; + } + } + + if (!document.getElementById('cpassword').value || + !document.getElementById('cpassword2').value || + pwok === 0) + en_change = 0; + + if (document.getElementById('showdel').checked) + document.getElementById('delete').style.display = "inline"; + else + document.getElementById('delete').style.display = "none"; + + document.getElementById('change').disabled = !en_change; + document.getElementById('cpassword').disabled = pwok === 0; + document.getElementById('cpassword2').disabled = pwok === 0; + document.getElementById('showdel').disabled = pwok === 0; + document.getElementById('delete').disabled = pwok === 0; + //document.getElementById('cemail').disabled = pwok === 0; + + /* + if (lwsgs_auth & 8) { + document.getElementById('cemail').style.display = "none"; + document.getElementById('cemail_name').style.display = "none"; + } else { + document.getElementById('cemail').style.display = "inline"; + document.getElementById('cemail_name').style.display = "inline"; + if (lwsgs_email_check === '0' && + document.getElementById('cemail').value != lwsgs_email) { + if (document.getElementById('cemail').value) + document.getElementById('cechk').innerHTML = "\u2713"; + else + document.getElementById('cechk').innerHTML = ""; + } else { + document.getElementById('cechk').innerHTML = "\u2718 Already registered"; + en_forgot = 1; + } + } */ + + if (lwsgs_auth & 8) + en_forgot = 0; + + if (en_forgot) + document.getElementById('cforgot').style.display = "inline"; + else + document.getElementById('cforgot').style.display = "none"; + + if (pwok === 0) + op = '0.5'; + else + op = '1.0'; + document.getElementById('cpassword').style.opacity = op; + document.getElementById('cpassword2').style.opacity = op; + // document.getElementById('cemail').style.opacity = op; + } + +function lwsgs_check_user() +{ + var xmlHttp = new XMLHttpRequest(); + xmlHttp.onreadystatechange = function() { + if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { + lwsgs_user_check = xmlHttp.responseText; + lwsgs_rupdate(); + } + } + xmlHttp.open("GET", "lwsgs-check/username="+document.getElementById('rusername').value, true); + xmlHttp.send(null); +} + +function lwsgs_check_email(id) +{ + var xmlHttp = new XMLHttpRequest(); + xmlHttp.onreadystatechange = function() { + if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { + lwsgs_email_check = xmlHttp.responseText; + lwsgs_rupdate(); + } + } + xmlHttp.open("GET", "lwsgs-check/email="+document.getElementById(id).value, true); + xmlHttp.send(null); +} + +function rupdate_user() +{ + lwsgs_rupdate(); + lwsgs_check_user(); +} + +function rupdate_email() +{ + lwsgs_rupdate(); + lwsgs_check_email('email'); +} + +function cupdate_email() +{ + lwsgs_cupdate(); + lwsgs_check_email('cemail'); +} + + +function lwsgs_initial() +{ + document.getElementById('lwsgs').innerHTML = lwsgs_html; + + if (lwsgs_user) { + document.getElementById("curuser").innerHTML = + "currently logged in as " + lwsgs_san(lwsgs_user) + "
"; + + document.getElementById("ccuruser").innerHTML = + "Login settings for " + + lwsgs_san(lwsgs_user) + "
"; + } + + document.getElementById('username').oninput = lwsgs_update; + document.getElementById('username').onchange = lwsgs_update; + document.getElementById('password').oninput = lwsgs_update; + document.getElementById('password').onchange = lwsgs_update; + document.getElementById('doreg').onclick = lwsgs_open_registration; + document.getElementById('clink').onclick = lwsgs_select_change; + document.getElementById('cancel').onclick =lwsgs_cancel_registration; + document.getElementById('cancel2').onclick =lwsgs_cancel_registration; + document.getElementById('rpassword').oninput = lwsgs_rupdate; + document.getElementById('password2').oninput = lwsgs_rupdate; + document.getElementById('rusername').oninput = rupdate_user; + document.getElementById('email').oninput = rupdate_email; + document.getElementById('ccurpw').oninput = lwsgs_cupdate; + document.getElementById('cpassword').oninput = lwsgs_cupdate; + document.getElementById('cpassword2').oninput = lwsgs_cupdate; + + document.getElementById('showdel').onchange = lwsgs_cupdate; + + if (lwsgs_email) + document.getElementById('grav').innerHTML = + ""; + //if (lwsgs_email) + //document.getElementById('cemail').placeholder = lwsgs_email; + document.getElementById('cusername').value = lwsgs_user; + lwsgs_update(); + lwsgs_cupdate(); +} + +window.addEventListener("load", function() { + lwsgs_initial(); + document.getElementById("nolog").style.display = !!lwsgs_user ? "none" : "inline-block"; + document.getElementById("logged").style.display = !lwsgs_user ? "none" : "inline-block"; + + document.getElementById("msg").onkeyup = mupd; + document.getElementById("msg").onchange = mupd; + + var ws; + + function mb_format(s) + { + var r = "", n, wos = 0; + + for (n = 0; n < s.length; n++) { + if (s[n] == ' ') + wos = 0; + else { + wos++; + if (wos === 40) { + wos = 0; + r = r + ' '; + } + } + if (s[n] == '<') { + r = r + "<"; + continue; + } + if (s[n] == '\n') { + r = r + "
"; + continue; + } + + r = r + s[n]; + } + + return r; + } + + function add_div(n, m) + { + var q = document.getElementById(n); + var d = new Date(m.time * 1000), s = d.toTimeString(), t; + + t = s.indexOf('('); + if (t) + s = s.substring(0, t); + + q.innerHTML = "
" + + "
" + + "" + lwsgs_san(m.username) + "
" + + "" + d.toDateString() + + "
" + s + "

" + + "IP: " + lwsgs_san(m.ip) + + "
" + + mb_format(m.content) + + "

" + q.innerHTML; + } + + function get_appropriate_ws_url() + { + var pcol; + var u = document.URL; + + if (u.substring(0, 5) == "https") { + pcol = "wss://"; + u = u.substr(8); + } else { + pcol = "ws://"; + if (u.substring(0, 4) == "http") + u = u.substr(7); + } + u = u.split('/'); + + return pcol + u[0] + "/xxx"; + } + + if (lwsgs_user) { + if (typeof MozWebSocket != "undefined") + ws = new MozWebSocket(get_appropriate_ws_url(), + "protocol-lws-messageboard"); + else + ws = new WebSocket(get_appropriate_ws_url(), + "protocol-lws-messageboard"); + + try { + ws.onopen = function() { + document.getElementById("debug").textContent = "ws opened"; + } + ws.onmessage =function got_packet(msg) { + add_div("messages", JSON.parse(msg.data)); + } + ws.onclose = function(){ + } + } catch(exception) { + alert('

Error' + exception); + } + } + + function mupd() + { + document.getElementById("send").disabled = !document.getElementById("msg").value; + } +}, false); diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/md5.min.js b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/md5.min.js new file mode 100644 index 000000000..4bd9de1e9 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/md5.min.js @@ -0,0 +1,2 @@ +!function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t),e=(n>>16)+(t>>16)+(r>>16);return e<<16|65535&r}function r(n,t){return n<>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<>>9<<4)+14]=r;var e,i,a,h,d,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e>5]>>>t%32&255);return r}function h(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t>5]|=(255&n.charCodeAt(t/8))<16&&(o=i(o,8*n.length)),r=0;16>r;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(h(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="0123456789abcdef",o="";for(r=0;r>>4&15)+e.charAt(15&t);return o}function v(n){return unescape(encodeURIComponent(n))}function m(n){return d(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this); +//# sourceMappingURL=md5.min.js.map \ No newline at end of file diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needadmin/admin-login.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needadmin/admin-login.html new file mode 100644 index 000000000..113df9cd3 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needadmin/admin-login.html @@ -0,0 +1,5 @@ + +This is an example destination that will appear after successful Admin login. + +This URL cannot be served if you're not logged in as admin. + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needauth/successful-login.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needauth/successful-login.html new file mode 100644 index 000000000..dfc25cf74 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needauth/successful-login.html @@ -0,0 +1,4 @@ + +This is an example destination that will appear after successful non-Admin login + + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-fail.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-fail.html new file mode 100644 index 000000000..ead3d13ec --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-fail.html @@ -0,0 +1,5 @@ + +Sorry, something went wrong. + +Click here to continue. + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-ok.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-ok.html new file mode 100644 index 000000000..3e8e9cf59 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-ok.html @@ -0,0 +1,6 @@ + +This is a one-time password recovery login. + +Please click here and click your username at the top to reset your password. + + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-fail.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-fail.html new file mode 100644 index 000000000..063c3c50f --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-fail.html @@ -0,0 +1 @@ +Registration failed, sorry diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-ok.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-ok.html new file mode 100644 index 000000000..c00c3f3d2 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-ok.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + +
+ +
+ Your registration as is accepted,
+ you will receive an email shortly with instructions
+ to verify and enable the account for normal use.

+ The link is only valid for an hour, after that if it has
+ not been verified your account will be deleted. +
+ + + + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-fail.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-fail.html new file mode 100644 index 000000000..d1d89ca56 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-fail.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + +
+ +
+ Sorry, the link was invalid. +
+ + + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-ok.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-ok.html new file mode 100644 index 000000000..ae647fc5c --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-ok.html @@ -0,0 +1,25 @@ + + + + + + + + + + + + +
+ +
+ Thanks for signing up, your registration as is verified.
+
+ Click here to continue. +
+ + + + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/seats.jpg b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/seats.jpg new file mode 100644 index 000000000..5bed40d91 Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/seats.jpg differ diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-fail.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-fail.html new file mode 100644 index 000000000..ead3d13ec --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-fail.html @@ -0,0 +1,5 @@ + +Sorry, something went wrong. + +Click here to continue. + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-ok.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-ok.html new file mode 100644 index 000000000..83df7510a --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-ok.html @@ -0,0 +1,4 @@ +An email has been sent to your registered address. + +Please follow the instructions to reset your password. + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/strict-csp.svg b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/strict-csp.svg new file mode 100644 index 000000000..cd128f1d2 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/strict-csp.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/successful-login.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/successful-login.html new file mode 100644 index 000000000..dfc25cf74 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/successful-login.html @@ -0,0 +1,4 @@ + +This is an example destination that will appear after successful non-Admin login + + diff --git a/minimal-examples/ws-server/minimal-ws-server-echo/protocol_lws_minimal_server_echo.c b/minimal-examples/ws-server/minimal-ws-server-echo/protocol_lws_minimal_server_echo.c index 337b6a080..b2a55314b 100644 --- a/minimal-examples/ws-server/minimal-ws-server-echo/protocol_lws_minimal_server_echo.c +++ b/minimal-examples/ws-server/minimal-ws-server-echo/protocol_lws_minimal_server_echo.c @@ -93,7 +93,8 @@ callback_minimal_server_echo(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_ESTABLISHED: - lwsl_user("LWS_CALLBACK_ESTABLISHED\n"); + /* generate a block of output before travis times us out */ + lwsl_warn("LWS_CALLBACK_ESTABLISHED\n"); pss->ring = lws_ring_create(sizeof(struct msg), RING_DEPTH, __minimal_destroy_message); if (!pss->ring) diff --git a/plugins/generic-sessions/handlers.c b/plugins/generic-sessions/handlers.c index ade66f2c6..d4fd35a56 100644 --- a/plugins/generic-sessions/handlers.c +++ b/plugins/generic-sessions/handlers.c @@ -1,7 +1,7 @@ /* * ws protocol handler plugin for "generic sessions" * - * Copyright (C) 2010-2016 Andy Green + * Copyright (C) 2010-2019 Andy Green * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,27 +21,65 @@ #include "private-lwsgs.h" +static int +lwsgs_smtp_client_done(struct lws_smtp_email *e, void *buf, size_t len) +{ + free(e); + + return 0; +} + +static int +lwsgs_smtp_client_done_sentvfy(struct lws_smtp_email *e, void *buf, size_t len) +{ + struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)e->data; + const char *username = (const char *)e->extra; + char s[200], esc[96]; + + lwsl_notice("%s: registration email sent: %s\n", __func__, username); + + /* mark the user as having sent the verification email */ + lws_snprintf(s, sizeof(s) - 1, + "update users set verified=1 where username='%s' and verified==0;", + lws_sql_purify(esc, username, sizeof(esc) - 1)); + if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) { + lwsl_err("%s: Unable to update user: %s\n", __func__, + sqlite3_errmsg(vhd->pdb)); + return 1; + } + + free(e); + + return 0; +} + /* handle account confirmation links */ int lwsgs_handler_confirm(struct per_vhost_data__gs *vhd, struct lws *wsi, struct per_session_data__gs *pss) { - char cookie[1024], s[256], esc[50]; + char cookie[1024], s[256], esc[90]; struct lws_gs_event_args a; struct lwsgs_user u; if (lws_hdr_copy_fragment(wsi, cookie, sizeof(cookie), - WSI_TOKEN_HTTP_URI_ARGS, 0) < 0) + WSI_TOKEN_HTTP_URI_ARGS, 0) < 0) { + lwsl_err("%s: missing URI_ARGS\n", __func__); goto verf_fail; + } - if (strncmp(cookie, "token=", 6)) + if (strncmp(cookie, "token=", 6)) { + lwsl_err("%s: missing URI_ARGS token=\n", __func__); goto verf_fail; + } u.username[0] = '\0'; + u.verified = -1; lws_snprintf(s, sizeof(s) - 1, "select username,email,verified from users where token = '%s';", lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1)); + puts(s); if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) != SQLITE_OK) { lwsl_err("Unable to lookup token: %s\n", @@ -50,7 +88,8 @@ lwsgs_handler_confirm(struct per_vhost_data__gs *vhd, struct lws *wsi, } if (!u.username[0] || u.verified != 1) { - lwsl_notice("verify token doesn't map to unverified user\n"); + lwsl_notice("verify token %s doesn't map to unverified user (user='%s', verified=%d)\n", + &cookie[6], u.username, u.verified); goto verf_fail; } @@ -111,7 +150,7 @@ int lwsgs_handler_forgot(struct per_vhost_data__gs *vhd, struct lws *wsi, struct per_session_data__gs *pss) { - char cookie[1024], s[256], esc[50]; + char cookie[1024], s[256], esc[96]; struct lwsgs_user u; const char *a; @@ -196,26 +235,24 @@ forgot_fail: int lwsgs_handler_check(struct per_vhost_data__gs *vhd, - struct lws *wsi, struct per_session_data__gs *pss) + struct lws *wsi, struct per_session_data__gs *pss, + const char *in) { static const char * const colname[] = { "username", "email" }; - char cookie[1024], s[256], esc[50], *pc; - unsigned char *p, *start, *end, buffer[LWS_PRE + 256]; + char s[256], esc[96], *pc; + unsigned char *p, *start, *end, buffer[LWS_PRE + 1024]; struct lwsgs_user u; int n; /* - * either /check?email=xxx@yyy or: /check?username=xxx + * either /check/email=xxx@yyy or: /check/username=xxx * returns '0' if not already registered, else '1' */ u.username[0] = '\0'; - if (lws_hdr_copy_fragment(wsi, cookie, sizeof(cookie), - WSI_TOKEN_HTTP_URI_ARGS, 0) < 0) - goto reply; - n = !strncmp(cookie, "email=", 6); - pc = strchr(cookie, '='); + n = !strncmp(in, "email=", 6); + pc = strchr(in, '='); if (!pc) { lwsl_notice("cookie has no =\n"); goto reply; @@ -262,6 +299,7 @@ reply: lwsl_err("_write returned %d from %ld\n", n, (long)(p - start)); return -1; } + pss->check_response_value = s[0]; pss->check_response = 1; @@ -276,7 +314,7 @@ int lwsgs_handler_change_password(struct per_vhost_data__gs *vhd, struct lws *wsi, struct per_session_data__gs *pss) { - char s[256], esc[50], username[50]; + char s[256], esc[96], username[96]; struct lwsgs_user u; lwsgw_hash sid; int n = 0; @@ -361,15 +399,14 @@ sql: int lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd, - struct lws *wsi, - struct per_session_data__gs *pss) + struct lws *wsi, struct per_session_data__gs *pss) { + char esc[96], esc1[96], esc2[96], esc3[96], esc4[96]; char s[LWSGS_EMAIL_CONTENT_SIZE]; - unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE]; - char esc[50], esc1[50], esc2[50], esc3[50], esc4[50]; + unsigned char sid_rand[32]; + lws_smtp_email_t *em; struct lwsgs_user u; lwsgw_hash hash; - unsigned char sid_rand[20]; int n; lwsl_notice("FORGOT %s %s\n", @@ -423,7 +460,19 @@ lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd, lwsl_err("Problem getting random for token\n"); return 1; } - sha1_to_lwsgw_hash(sid_rand, &hash); + sha256_to_lwsgw_hash(sid_rand, &hash); + + lws_snprintf(s, sizeof(s) - 1, + "update users set token='%s',token_time='%ld' where username='%s';", + hash.id, (long)lws_now_secs(), + lws_sql_purify(esc, u.username, sizeof(esc) - 1)); + if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != + SQLITE_OK) { + lwsl_err("Unable to set token: %s\n", + sqlite3_errmsg(vhd->pdb)); + return 1; + } + n = lws_snprintf(s, sizeof(s), "From: Forgot Password Assistant Noreply <%s>\n" "To: %s <%s>\n" @@ -437,7 +486,7 @@ lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd, lws_sql_purify(esc2, u.email, sizeof(esc2) - 1), lws_sql_purify(esc3, u.username, sizeof(esc3) - 1), lws_sql_purify(esc4, pss->ip, sizeof(esc4) - 1)); - lws_snprintf(s + n, sizeof(s) -n, + n += lws_snprintf(s + n, sizeof(s) - n, "%s/lwsgs-forgot?token=%s" "&good=%s" "&bad=%s\n\n" @@ -456,27 +505,15 @@ lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd, sizeof(esc3) - 1), vhd->email_contact_person); - lws_snprintf((char *)buffer, sizeof(buffer) - 1, - "insert into email(username, content)" - " values ('%s', '%s');", - lws_sql_purify(esc, u.username, sizeof(esc) - 1), s); - if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL, - NULL, NULL) != SQLITE_OK) { - lwsl_err("Unable to insert email: %s\n", - sqlite3_errmsg(vhd->pdb)); - return 1; - } + puts(s); - lws_snprintf(s, sizeof(s) - 1, - "update users set token='%s',token_time='%ld' where username='%s';", - hash.id, (long)lws_now_secs(), - lws_sql_purify(esc, u.username, sizeof(esc) - 1)); - if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != - SQLITE_OK) { - lwsl_err("Unable to set token: %s\n", - sqlite3_errmsg(vhd->pdb)); + em = lws_smtp_client_alloc_email_helper(s, n, vhd->email_from, u.email, + u.username, strlen(u.username), + vhd, lwsgs_smtp_client_done); + if (!em) + return 1; + if (lws_smtp_client_add_email(vhd->smtp_client, em)) return 1; - } return 0; } @@ -487,11 +524,13 @@ lwsgs_handler_register_form(struct per_vhost_data__gs *vhd, struct per_session_data__gs *pss) { unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE]; - char esc[50], esc1[50], esc2[50], esc3[50], esc4[50]; + char esc[96], esc1[96], esc2[96], esc3[96], esc4[96]; char s[LWSGS_EMAIL_CONTENT_SIZE]; - unsigned char sid_rand[20]; + unsigned char sid_rand[32]; + lws_smtp_email_t *em; struct lwsgs_user u; lwsgw_hash hash; + size_t n; lwsl_notice("REGISTER %s %s %s\n", lws_spa_get_string(pss->spa, FGS_USERNAME), @@ -551,7 +590,7 @@ lwsgs_handler_register_form(struct per_vhost_data__gs *vhd, lwsl_err("Problem getting random for token\n"); return 1; } - sha1_to_lwsgw_hash(sid_rand, &hash); + sha256_to_lwsgw_hash(sid_rand, &hash); lws_snprintf((char *)buffer, sizeof(buffer) - 1, "insert into users(username," @@ -571,11 +610,11 @@ lwsgs_handler_register_form(struct per_vhost_data__gs *vhd, return 1; } - lws_snprintf(s, sizeof(s), + n = lws_snprintf(s, sizeof(s), "From: Noreply <%s>\n" "To: %s <%s>\n" - "Subject: Registration verification\n" - "\n" + "Subject: Registration verification\n" + "\n" "Hello, %s\n\n" "We received a registration from IP %s using this email,\n" "to confirm it is legitimate, please click the link below.\n\n" @@ -594,16 +633,16 @@ lwsgs_handler_register_form(struct per_vhost_data__gs *vhd, vhd->email_confirm_url, hash.id, vhd->email_contact_person); - lws_snprintf((char *)buffer, sizeof(buffer) - 1, - "insert into email(username, content) values ('%s', '%s');", - lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME), - sizeof(esc) - 1), s); - - if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL, NULL, NULL) != SQLITE_OK) { - lwsl_err("Unable to insert email: %s\n", - sqlite3_errmsg(vhd->pdb)); + em = lws_smtp_client_alloc_email_helper(s, n, vhd->email_from, + lws_spa_get_string(pss->spa, FGS_EMAIL), + lws_spa_get_string(pss->spa, FGS_USERNAME), + strlen(lws_spa_get_string(pss->spa, FGS_USERNAME)), + vhd, lwsgs_smtp_client_done_sentvfy); + if (!em) + return 1; + + if (lws_smtp_client_add_email(vhd->smtp_client, em)) return 1; - } return 0; } diff --git a/plugins/generic-sessions/private-lwsgs.h b/plugins/generic-sessions/private-lwsgs.h index 0829b479e..c9d9bca44 100644 --- a/plugins/generic-sessions/private-lwsgs.h +++ b/plugins/generic-sessions/private-lwsgs.h @@ -67,6 +67,7 @@ struct per_vhost_data__gs { struct lws_context *context; char session_db[256]; char admin_user[32]; + char urlroot[48]; char confounder[32]; char email_contact_person[128]; char email_title[128]; @@ -119,7 +120,7 @@ int lwsgs_check_credentials(struct per_vhost_data__gs *vhd, const char *username, const char *password); void -sha1_to_lwsgw_hash(unsigned char *hash, lwsgw_hash *shash); +sha256_to_lwsgw_hash(unsigned char *hash, lwsgw_hash *shash); unsigned int lwsgs_now_secs(void); int @@ -151,7 +152,7 @@ lwsgs_handler_forgot(struct per_vhost_data__gs *vhd, struct lws *wsi, struct per_session_data__gs *pss); int lwsgs_handler_check(struct per_vhost_data__gs *vhd, struct lws *wsi, - struct per_session_data__gs *pss); + struct per_session_data__gs *pss, const char *in); int lwsgs_handler_change_password(struct per_vhost_data__gs *vhd, struct lws *wsi, struct per_session_data__gs *pss); diff --git a/plugins/generic-sessions/protocol_generic_sessions.c b/plugins/generic-sessions/protocol_generic_sessions.c index 5d965ee05..88096fa9f 100644 --- a/plugins/generic-sessions/protocol_generic_sessions.c +++ b/plugins/generic-sessions/protocol_generic_sessions.c @@ -50,141 +50,6 @@ struct lwsgs_fill_args { }; static const struct lws_protocols protocols[]; -#if 0 -static int -lwsgs_lookup_callback_email(void *priv, int cols, char **col_val, - char **col_name) -{ - struct lwsgs_fill_args *a = (struct lwsgs_fill_args *)priv; - int n; - - for (n = 0; n < cols; n++) { - if (!strcmp(col_name[n], "content")) { - lws_strncpy(a->buf, col_val[n], a->len); - continue; - } - } - return 0; -} - -static int -lwsgs_email_cb_get_body(struct lws_email *email, char *buf, int len) -{ - struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)email->data; - struct lwsgs_fill_args a; - char ss[150], esc[50]; - - a.buf = buf; - a.len = len; - - lws_snprintf(ss, sizeof(ss) - 1, - "select content from email where username='%s';", - lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1)); - - lws_strncpy(buf, "failed", len); - if (sqlite3_exec(vhd->pdb, ss, lwsgs_lookup_callback_email, &a, - NULL) != SQLITE_OK) { - lwsl_err("Unable to lookup email: %s\n", - sqlite3_errmsg(vhd->pdb)); - - return 1; - } - - return 0; -} -#endif - -#if 0 -static int -lwsgs_smtp_client_done(struct lws_smtp_email *e, void *buf, size_t len) -{ - struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)e->data; - char s[200], esc[50]; - - /* mark the user as having sent the verification email */ - lws_snprintf(s, sizeof(s) - 1, - "update users set verified=1 where username='%s' and verified==0;", - lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1)); - if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) { - lwsl_err("%s: Unable to update user: %s\n", __func__, - sqlite3_errmsg(vhd->pdb)); - return 1; - } - - lws_snprintf(s, sizeof(s) - 1, - "delete from email where username='%s';", - lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1)); - if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) { - lwsl_err("%s: Unable to delete email text: %s\n", __func__, - sqlite3_errmsg(vhd->pdb)); - return 1; - } - - return 0; -} -#endif -#if 0 -static int -lwsgs_smtp_send_pending(struct lws_email *email) -{ - struct per_vhost_data__gs *vhd = lws_container_of(email, - struct per_vhost_data__gs, email); - char s[LWSGS_EMAIL_CONTENT_SIZE], esc[50]; - time_t now = lws_now_secs(); - - /* - * users not verified in 24h get deleted - */ - lws_snprintf(s, sizeof(s) - 1, "delete from users where ((verified != %d)" - " and (creation_time <= %lu));", LWSGS_VERIFIED_ACCEPTED, - (unsigned long)now - vhd->timeout_email_secs); - if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) { - lwsl_err("Unable to expire users: %s\n", - sqlite3_errmsg(vhd->pdb)); - return 1; - } - - lws_snprintf(s, sizeof(s) - 1, "update users set token_time=0 where " - "(token_time <= %lu);", - (unsigned long)now - vhd->timeout_email_secs); - if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) { - lwsl_err("Unable to expire users: %s\n", - sqlite3_errmsg(vhd->pdb)); - return 1; - } - - vhd->u.username[0] = '\0'; - lws_snprintf(s, sizeof(s) - 1, "select username from email limit 1;"); - if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &vhd->u, - NULL) != SQLITE_OK) { - lwsl_err("Unable to lookup user: %s\n", sqlite3_errmsg(vhd->pdb)); - return 1; - } - - lws_snprintf(s, sizeof(s) - 1, - "select username, creation_time, email, ip, verified, token" - " from users where username='%s' limit 1;", - lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1)); - if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &vhd->u, - NULL) != SQLITE_OK) { - lwsl_err("Unable to lookup user: %s\n", - sqlite3_errmsg(vhd->pdb)); - return 1; - } - - if (!vhd->u.username[0]) - /* - * nothing to do, we are idle and no suitable - * accounts waiting for verification. When a new user - * is added we will get kicked to try again. - */ - return 1; - - lws_strncpy(email->email_to, vhd->u.email, sizeof(email->email_to)); - - return 0; -} -#endif struct lwsgs_subst_args { @@ -199,7 +64,7 @@ lwsgs_subst(void *data, int index) struct lwsgs_subst_args *a = (struct lwsgs_subst_args *)data; struct lwsgs_user u; lwsgw_hash sid; - char esc[50], s[100]; + char esc[96], s[100]; int n; a->pss->result[0] = '\0'; @@ -240,6 +105,21 @@ lwsgs_subst(void *data, int index) return NULL; } +static int +lws_get_effective_host(struct lws *wsi, char *buf, size_t buflen) +{ + /* h2 */ + if (lws_hdr_copy(wsi, buf, buflen - 1, + WSI_TOKEN_HTTP_COLON_AUTHORITY) > 0) + return 0; + + /* h1 */ + if (lws_hdr_copy(wsi, buf, buflen - 1, WSI_TOKEN_HOST) > 0) + return 0; + + return 1; +} + static int callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) @@ -248,24 +128,25 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, const struct lws_protocol_vhost_options *pvo; struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *) lws_protocol_vh_priv_get(lws_get_vhost(wsi), - &protocols[0]); + lws_vhost_name_to_protocol(lws_get_vhost(wsi), + "protocol-generic-sessions")); char cookie[1024], username[32], *pc = cookie; unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE]; - struct lws_process_html_args *args; + struct lws_process_html_args *args = in; struct lws_session_info *sinfo; char s[LWSGS_EMAIL_CONTENT_SIZE]; unsigned char *p, *start, *end; lws_smtp_client_info_t sci; + const char *cp, *cp1; sqlite3_stmt *sm; lwsgw_hash sid; - const char *cp; int n; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), - &protocols[0], sizeof(struct per_vhost_data__gs)); + lws_get_protocol(wsi), sizeof(struct per_vhost_data__gs)); if (!vhd) return 1; vhd->context = lws_get_context(wsi); @@ -282,13 +163,17 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, strcpy(sci.ip, "127.0.0.1"); strcpy(vhd->email_from, "noreply@unconfigured.com"); strcpy(vhd->email_title, "Registration Email from unconfigured"); + vhd->urlroot[0] = '\0'; pvo = (const struct lws_protocol_vhost_options *)in; while (pvo) { if (!strcmp(pvo->name, "admin-user")) lws_strncpy(vhd->admin_user, pvo->value, sizeof(vhd->admin_user)); - if (!strcmp(pvo->name, "admin-password-sha1")) + if (!strcmp(pvo->name, "urlroot")) + lws_strncpy(vhd->urlroot, pvo->value, + sizeof(vhd->urlroot)); + if (!strcmp(pvo->name, "admin-password-sha256")) lws_strncpy(vhd->admin_password_sha256.id, pvo->value, sizeof(vhd->admin_password_sha256.id)); if (!strcmp(pvo->name, "session-db")) @@ -337,9 +222,8 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, return 1; } - if (sqlite3_open_v2(vhd->session_db, &vhd->pdb, - SQLITE_OPEN_READWRITE | - SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) { + if (lws_struct_sq3_open(lws_get_context(wsi), + vhd->session_db, &vhd->pdb)) { lwsl_err("Unable to open session db %s: %s\n", vhd->session_db, sqlite3_errmsg(vhd->pdb)); @@ -348,7 +232,7 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, if (sqlite3_prepare(vhd->pdb, "create table if not exists sessions (" - " name char(40)," + " name char(65)," " username varchar(32)," " expire integer" ");", @@ -373,10 +257,10 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, " creation_time integer," " ip varchar(46)," " email varchar(100)," - " pwhash varchar(42)," - " pwsalt varchar(42)," + " pwhash varchar(65)," + " pwsalt varchar(65)," " pwchange_time integer," - " token varchar(42)," + " token varchar(65)," " verified integer," " token_time integer," " last_forgot_validated integer," @@ -389,18 +273,6 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, return 1; } - sprintf(s, "create table if not exists email (" - " username varchar(32)," - " content blob," - " primary key (username)" - ");"); - if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) { - lwsl_err("Unable to create user table: %s\n", - sqlite3_errmsg(vhd->pdb)); - - return 1; - } - sci.data = vhd; sci.abs = lws_abstract_get_by_name("raw_skt"); sci.vh = lws_get_vhost(wsi); @@ -411,6 +283,8 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, return 1; } + lwsl_notice("%s: created SMTP client\n", __func__); + break; case LWS_CALLBACK_PROTOCOL_DESTROY: @@ -426,72 +300,112 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_HTTP_WRITEABLE: if (!pss->check_response) break; + pss->check_response = 0; n = lws_write(wsi, (unsigned char *)&pss->check_response_value, - 1, LWS_WRITE_HTTP_FINAL); + 1, LWS_WRITE_HTTP | LWS_WRITE_H2_STREAM_END); if (n != 1) return -1; goto try_to_reuse; case LWS_CALLBACK_HTTP: - lwsl_info("LWS_CALLBACK_HTTP: %s\n", (const char *)in); + if (!pss) { + lwsl_err("%s: no valid pss\n", __func__); + return 1; + } pss->login_session.id[0] = '\0'; pss->phs.pos = 0; - lws_strncpy(pss->onward, (char *)in, sizeof(pss->onward)); - if (!strcmp((const char *)in, "/lwsgs-forgot")) { + cp = in; + if ((*(const char *)in == '/')) + cp++; + + if (lws_get_effective_host(wsi, cookie, sizeof(cookie))) { + lwsl_err("%s: HTTP: no effective host\n", __func__); + return 1; + } + + lwsl_notice("LWS_CALLBACK_HTTP: %s, HOST '%s'\n", + (const char *)in, cookie); + + n = strlen(cp); + + lws_snprintf(pss->onward, sizeof(pss->onward), + "%s%s", vhd->urlroot, (const char *)in); + + if (n >= 12 && + !strcmp(cp + n - 12, "lwsgs-forgot")) { lwsgs_handler_forgot(vhd, wsi, pss); goto redirect_with_cookie; } - if (!strcmp((const char *)in, "/lwsgs-confirm")) { + if (n >= 13 && + !strcmp(cp + n - 13, "lwsgs-confirm")) { lwsgs_handler_confirm(vhd, wsi, pss); goto redirect_with_cookie; } - if (!strcmp((const char *)in, "/lwsgs-check")) { - lwsgs_handler_check(vhd, wsi, pss); + cp = strstr(cp, "lwsgs-check/"); + if (cp) { + lwsgs_handler_check(vhd, wsi, pss, cp + 12); /* second, async part will complete transaction */ break; } - if (!strcmp((const char *)in, "/lwsgs-login")) + if (n >= 11 && !strcmp(cp + n - 11, "lwsgs-login")) break; - if (!strcmp((const char *)in, "/lwsgs-logout")) + if (n >= 12 && !strcmp(cp + n - 12, "lwsgs-logout")) break; - if (!strcmp((const char *)in, "/lwsgs-forgot")) + if (n >= 12 && !strcmp(cp + n - 12, "lwsgs-forgot")) break; - if (!strcmp((const char *)in, "/lwsgs-change")) + if (n >= 12 && !strcmp(cp + n - 12, "lwsgs-change")) break; /* if no legitimate url for GET, return 404 */ - lwsl_err("http doing 404 on %s\n", (const char *)in); + lwsl_err("http doing 404 on %s\n", cp); lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL); + return -1; //goto try_to_reuse; + case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: + args = (struct lws_process_html_args *)in; + if (!args->chunked) + break; case LWS_CALLBACK_CHECK_ACCESS_RIGHTS: n = 0; username[0] = '\0'; sid.id[0] = '\0'; args = (struct lws_process_html_args *)in; - lwsl_debug("LWS_CALLBACK_CHECK_ACCESS_RIGHTS\n"); + lwsl_notice("%s: LWS_CALLBACK_CHECK_ACCESS_RIGHTS: need 0x%x\n", + __func__, args->max_len); if (!lwsgs_get_sid_from_wsi(wsi, &sid)) { - if (lwsgs_lookup_session(vhd, &sid, username, sizeof(username))) { - static const char * const oprot[] = { - "http://", "https://" - }; - lwsl_notice("session lookup for %s failed, probably expired\n", sid.id); + if (lwsgs_lookup_session(vhd, &sid, username, + sizeof(username))) { + + /* + * if we're authenticating for ws, we don't + * want to redirect it or gain a cookie on that, + * he'll need to get the cookie from http + * interactions outside of this. + */ + if (args->chunked) { + lwsl_notice("%s: ws auth failed\n", + __func__); + + return 1; + } + + lwsl_notice("session lookup for %s failed, " + "probably expired\n", sid.id); pss->delete_session = sid; args->final = 1; /* signal we dealt with it */ - if (lws_hdr_copy(wsi, cookie, sizeof(cookie) - 1, - WSI_TOKEN_HOST) < 0) - return 1; lws_snprintf(pss->onward, sizeof(pss->onward) - 1, - "%s%s%s", oprot[!!lws_is_ssl(wsi)], - cookie, args->p); - lwsl_notice("redirecting to ourselves with cookie refresh\n"); - /* we need a redirect to ourselves, session cookie is expired */ + "%s%s", vhd->urlroot, args->p); + lwsl_notice("redirecting to ourselves with " + "cookie refresh\n"); + /* we need a redirect to ourselves, + * session cookie is expired */ goto redirect_with_cookie; } } else @@ -590,10 +504,18 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, if (!pss->spa) break; - lwsl_info("LWS_CALLBACK_HTTP_BODY_COMPLETION: %s\n", pss->onward); - lws_spa_finalize(pss->spa); + cp1 = (const char *)pss->onward; + if (*cp1 == '/') + cp1++; - if (!strcmp((char *)pss->onward, "/lwsgs-change")) { + + lws_spa_finalize(pss->spa); + n = strlen(cp1); + + if (lws_get_effective_host(wsi, cookie, sizeof(cookie))) + return 1; + + if (!strcmp(cp1 + n - 12, "lwsgs-change")) { if (!lwsgs_handler_change_password(vhd, wsi, pss)) { cp = lws_spa_get_string(pss->spa, FGS_GOOD); goto pass; @@ -602,12 +524,15 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, cp = lws_spa_get_string(pss->spa, FGS_BAD); lwsl_notice("user/password no good %s\n", lws_spa_get_string(pss->spa, FGS_USERNAME)); - lws_strncpy(pss->onward, cp, sizeof(pss->onward) - 1); + lws_snprintf(pss->onward, sizeof(pss->onward), + "%s%s", vhd->urlroot, cp); + pss->onward[sizeof(pss->onward) - 1] = '\0'; goto completion_flow; } - if (!strcmp((char *)pss->onward, "/lwsgs-login")) { + if (!strcmp(cp1 + n - 11, "lwsgs-login")) { + lwsl_err("%s: lwsgs-login\n", __func__); if (lws_spa_get_string(pss->spa, FGS_FORGOT) && lws_spa_get_string(pss->spa, FGS_FORGOT)[0]) { if (lwsgs_handler_forgot_pw_form(vhd, wsi, pss)) { @@ -623,8 +548,8 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, if (!lws_spa_get_string(pss->spa, FGS_USERNAME) || !lws_spa_get_string(pss->spa, FGS_PASSWORD)) { lwsl_notice("username '%s' or pw '%s' missing\n", - lws_spa_get_string(pss->spa, FGS_USERNAME), - lws_spa_get_string(pss->spa, FGS_PASSWORD)); + lws_spa_get_string(pss->spa, FGS_USERNAME), + lws_spa_get_string(pss->spa, FGS_PASSWORD)); return -1; } @@ -640,8 +565,10 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason, lws_smtp_client_kick(vhd->smtp_client); } reg_done: - lws_strncpy(pss->onward, lws_spa_get_string(pss->spa, n), - sizeof(pss->onward)); + lws_snprintf(pss->onward, sizeof(pss->onward), + "%s%s", vhd->urlroot, + lws_spa_get_string(pss->spa, n)); + pss->login_expires = 0; pss->logging_out = 1; goto completion_flow; @@ -665,28 +592,32 @@ reg_done: /* check users in database */ - if (!lwsgs_check_credentials(vhd, lws_spa_get_string(pss->spa, FGS_USERNAME), - lws_spa_get_string(pss->spa, FGS_PASSWORD))) { - lwsl_info("pw hash check met\n"); + if (!lwsgs_check_credentials(vhd, + lws_spa_get_string(pss->spa, FGS_USERNAME), + lws_spa_get_string(pss->spa, FGS_PASSWORD))) { + lwsl_notice("pw hash check met\n"); cp = lws_spa_get_string(pss->spa, FGS_GOOD); goto pass; } else - lwsl_notice("user/password no good %s\n", - lws_spa_get_string(pss->spa, FGS_USERNAME)); + lwsl_notice("user/password no good %s %s\n", + lws_spa_get_string(pss->spa, FGS_USERNAME), + lws_spa_get_string(pss->spa, FGS_PASSWORD)); if (!lws_spa_get_string(pss->spa, FGS_BAD)) { lwsl_info("No admin or good target url in form\n"); return -1; } - lws_strncpy(pss->onward, lws_spa_get_string(pss->spa, FGS_BAD), - sizeof(pss->onward)); - lwsl_debug("failed\n"); + lws_snprintf(pss->onward, sizeof(pss->onward), + "%s%s", vhd->urlroot, + lws_spa_get_string(pss->spa, FGS_BAD)); + + lwsl_notice("failed: %s\n", pss->onward); goto completion_flow; } - if (!strcmp((char *)pss->onward, "/lwsgs-logout")) { + if (!strcmp(cp1 + n - 12, "lwsgs-logout")) { lwsl_notice("/logout\n"); @@ -695,6 +626,11 @@ reg_done: return 1; } + /* + * We keep the same session, but mark it as not + * being associated to any authenticated user + */ + lwsgw_update_session(vhd, &pss->login_session, ""); if (!lws_spa_get_string(pss->spa, FGS_GOOD)) { @@ -702,8 +638,9 @@ reg_done: return -1; } - lws_strncpy(pss->onward, lws_spa_get_string(pss->spa, FGS_GOOD), - sizeof(pss->onward)); + lws_snprintf(pss->onward, sizeof(pss->onward), + "%s%s", vhd->urlroot, + lws_spa_get_string(pss->spa, FGS_GOOD)); pss->login_expires = 0; pss->logging_out = 1; @@ -714,7 +651,8 @@ reg_done: break; pass: - lws_strncpy(pss->onward, cp, sizeof(pss->onward)); + lws_snprintf(pss->onward, sizeof(pss->onward), + "%s%s", vhd->urlroot, cp); if (lwsgs_get_sid_from_wsi(wsi, &sid)) sid.id[0] = '\0'; @@ -726,18 +664,18 @@ pass: /* we need to create a new, authorized session */ if (lwsgs_new_session_id(vhd, &pss->login_session, - lws_spa_get_string(pss->spa, FGS_USERNAME), - pss->login_expires)) + lws_spa_get_string(pss->spa, FGS_USERNAME), + pss->login_expires)) goto try_to_reuse; - lwsl_info("Creating new session: %s\n", + lwsl_notice("Creating new session: %s\n", pss->login_session.id); } else { /* * we can just update the existing session to be * authorized */ - lwsl_info("Authorizing existing session %s", sid.id); + lwsl_notice("Authorizing existing session %s", sid.id); lwsgw_update_session(vhd, &sid, lws_spa_get_string(pss->spa, FGS_USERNAME)); pss->login_session = sid; @@ -757,6 +695,8 @@ completion_flow: case LWS_CALLBACK_ADD_HEADERS: lwsgw_expire_old_sessions(vhd); + lwsl_warn("ADD_HEADERS\n"); + args = (struct lws_process_html_args *)in; if (!pss) return 1; @@ -765,7 +705,7 @@ completion_flow: lwsgw_cookie_from_session(&pss->delete_session, 0, &pc, cookie + sizeof(cookie) - 1); - lwsl_info("deleting cookie '%s'\n", cookie); + lwsl_notice("deleting cookie '%s'\n", cookie); if (lws_add_http_header_by_name(wsi, (unsigned char *)"set-cookie:", @@ -811,13 +751,24 @@ redirect_with_cookie: start = p; end = p + sizeof(buffer) - LWS_PRE; + lwsl_warn("%s: redirect_with_cookie\n", __func__); + if (lws_add_http_header_status(wsi, HTTP_STATUS_SEE_OTHER, &p, end)) return 1; - if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION, - (unsigned char *)pss->onward, - strlen(pss->onward), &p, end)) - return 1; + { + char loc[1024], uria[128]; + + uria[0] = '\0'; + lws_hdr_copy_fragment(wsi, uria, sizeof(uria), + WSI_TOKEN_HTTP_URI_ARGS, 0); + n = lws_snprintf(loc, sizeof(loc), "%s?%s", + pss->onward, uria); + lwsl_notice("%s: redirect to '%s'\n", __func__, loc); + if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION, + (unsigned char *)loc, n, &p, end)) + return 1; + } if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, &p, end)) @@ -834,16 +785,20 @@ redirect_with_cookie: if (lws_add_http_header_by_name(wsi, (unsigned char *)"set-cookie:", (unsigned char *)cookie, pc - cookie, - &p, end)) + &p, end)) { + lwsl_err("fail0\n"); return 1; + } } if (!pss->login_session.id[0]) { pss->login_expires = lws_now_secs() + vhd->timeout_anon_absolute_secs; if (lwsgs_new_session_id(vhd, &pss->login_session, "", - pss->login_expires)) + pss->login_expires)) { + lwsl_err("fail1\n"); return 1; + } } else pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs; @@ -859,21 +814,26 @@ redirect_with_cookie: pss->login_expires, &pc, cookie + sizeof(cookie) - 1); - lwsl_info("setting cookie '%s'\n", cookie); + lwsl_err("%s: setting cookie '%s'\n", __func__, cookie); pss->logging_out = 0; if (lws_add_http_header_by_name(wsi, (unsigned char *)"set-cookie:", (unsigned char *)cookie, pc - cookie, - &p, end)) + &p, end)) { + lwsl_err("fail2\n"); return 1; + } } if (lws_finalize_http_header(wsi, &p, end)) return 1; - n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); + // lwsl_hexdump_notice(start, p - start); + + n = lws_write(wsi, start, p - start, LWS_WRITE_H2_STREAM_END | + LWS_WRITE_HTTP_HEADERS); if (n < 0) return 1; diff --git a/plugins/generic-sessions/protocol_lws_messageboard.c b/plugins/generic-sessions/protocol_lws_messageboard.c index 7c3359f05..4fb973f03 100644 --- a/plugins/generic-sessions/protocol_lws_messageboard.c +++ b/plugins/generic-sessions/protocol_lws_messageboard.c @@ -1,7 +1,7 @@ /* * ws protocol handler plugin for messageboard "generic sessions" demo * - * Copyright (C) 2010-2016 Andy Green + * Copyright (C) 2010-2019 Andy Green * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -157,12 +157,13 @@ callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason, const struct lws_protocol_vhost_options *pvo; struct per_vhost_data__gs_mb *vhd = (struct per_vhost_data__gs_mb *) lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)); - unsigned char *p, *start, *end, buffer[LWS_PRE + 256]; + unsigned char *p, *start, *end, buffer[LWS_PRE + 4096]; char s[512]; int n; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ + vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct per_vhost_data__gs_mb)); if (!vhd) @@ -187,9 +188,8 @@ callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason, return 1; } - if (sqlite3_open_v2(vhd->message_db, &vhd->pdb, - SQLITE_OPEN_READWRITE | - SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) { + if (lws_struct_sq3_open(lws_get_context(wsi), + vhd->message_db, &vhd->pdb)) { lwsl_err("Unable to open message db %s: %s\n", vhd->message_db, sqlite3_errmsg(vhd->pdb)); @@ -226,6 +226,14 @@ callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason, lws_callback_on_writable(wsi); break; + case LWS_CALLBACK_CLOSED: + lwsl_debug("%s: LWS_CALLBACK_CLOSED\n", __func__); + if (pss && pss->pss_gs) { + free(pss->pss_gs); + pss->pss_gs = NULL; + } + break; + case LWS_CALLBACK_SERVER_WRITEABLE: { struct message m; @@ -279,7 +287,8 @@ callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason, pss->our_form = 0; /* ie, it's our messageboard new message form */ - if (!strcmp((const char *)in, "/msg")) { + if (!strcmp((const char *)in, "/msg") || + !strcmp((const char *)in, "msg")) { pss->our_form = 1; break; } @@ -308,9 +317,11 @@ callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_HTTP_WRITEABLE: if (!pss->second_http_part) - break; + goto passthru; + s[0] = '0'; - n = lws_write(wsi, (unsigned char *)s, 1, LWS_WRITE_HTTP); + n = lws_write(wsi, (unsigned char *)s, 1, LWS_WRITE_HTTP| + LWS_WRITE_H2_STREAM_END); if (n != 1) return -1; @@ -336,18 +347,18 @@ callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason, return -1; if (lws_finalize_http_header(wsi, &p, end)) return -1; + n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); if (n != (p - start)) { lwsl_err("_write returned %d from %ld\n", n, (long)(p - start)); return -1; } pss->second_http_part = 1; - lws_callback_on_writable(wsi); break; case LWS_CALLBACK_HTTP_BIND_PROTOCOL: - if (!pss || pss->pss_gs) + if (!pss || !vhd || pss->pss_gs) break; pss->pss_gs = malloc(vhd->gsp->per_session_data_size); @@ -375,6 +386,7 @@ callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason, passthru: if (!pss || !vhd) break; + return vhd->gsp->callback(wsi, reason, pss->pss_gs, in, len); } diff --git a/plugins/generic-sessions/utils.c b/plugins/generic-sessions/utils.c index 22a5cb561..0b8959bfe 100644 --- a/plugins/generic-sessions/utils.c +++ b/plugins/generic-sessions/utils.c @@ -23,13 +23,13 @@ #include void -sha1_to_lwsgw_hash(unsigned char *hash, lwsgw_hash *shash) +sha256_to_lwsgw_hash(unsigned char *hash, lwsgw_hash *shash) { static const char *hex = "0123456789abcdef"; char *p = shash->id; int n; - for (n = 0; n < 20; n++) { + for (n = 0; n < (int)lws_genhash_size(LWS_GENHASH_TYPE_SHA256); n++) { *p++ = hex[(hash[n] >> 4) & 0xf]; *p++ = hex[hash[n] & 15]; } @@ -48,7 +48,7 @@ lwsgw_check_admin(struct per_vhost_data__gs *vhd, return 0; lws_SHA1((unsigned char *)password, strlen(password), hash_bin.bin); - sha1_to_lwsgw_hash(hash_bin.bin, &pw_hash); + sha256_to_lwsgw_hash(hash_bin.bin, &pw_hash); return !strcmp(vhd->admin_password_sha256.id, pw_hash.id); } @@ -106,7 +106,7 @@ lwsgw_update_session(struct per_vhost_data__gs *vhd, lwsgw_hash *hash, const char *user) { time_t n = lws_now_secs(); - char s[200], esc[50], esc1[50]; + char s[200], esc[96], esc1[96]; if (user[0]) n += vhd->timeout_absolute_secs; @@ -125,6 +125,8 @@ lwsgw_update_session(struct per_vhost_data__gs *vhd, return 1; } + puts(s); + return 0; } @@ -183,7 +185,7 @@ lwsgs_get_sid_from_wsi(struct lws *wsi, lwsgw_hash *sid) } /* extract the sid from the cookie */ if (lwsgw_session_from_cookie(cookie, sid)) { - lwsl_info("session from cookie failed\n"); + lwsl_info("%s: session from cookie failed\n", __func__); return 1; } @@ -218,7 +220,7 @@ lwsgs_lookup_session(struct per_vhost_data__gs *vhd, const lwsgw_hash *sid, char *username, int len) { struct lla lla = { username, len, 1 }; - char s[150], esc[50]; + char s[150], esc[96]; lwsgw_expire_old_sessions(vhd); @@ -291,7 +293,7 @@ int lwsgs_lookup_user(struct per_vhost_data__gs *vhd, const char *username, struct lwsgs_user *u) { - char s[150], esc[50]; + char s[150], esc[96]; u->username[0] = '\0'; lws_snprintf(s, sizeof(s) - 1, @@ -314,17 +316,19 @@ int lwsgs_new_session_id(struct per_vhost_data__gs *vhd, lwsgw_hash *sid, const char *username, int exp) { - unsigned char sid_rand[20]; + unsigned char sid_rand[32]; const char *u; - char s[300], esc[50], esc1[50]; + char s[300], esc[96], esc1[96]; if (username) u = username; else u = ""; - if (!sid) + if (!sid) { + lwsl_err("%s: NULL sid\n", __func__); return 1; + } memset(sid, 0, sizeof(*sid)); @@ -332,7 +336,7 @@ lwsgs_new_session_id(struct per_vhost_data__gs *vhd, sizeof(sid_rand)) return 1; - sha1_to_lwsgw_hash(sid_rand, sid); + sha256_to_lwsgw_hash(sid_rand, sid); lws_snprintf(s, sizeof(s) - 1, "insert into sessions(name, username, expire) " @@ -347,27 +351,28 @@ lwsgs_new_session_id(struct per_vhost_data__gs *vhd, return 1; } + lwsl_notice("%s: created session %s\n", __func__, sid->id); + return 0; } int -lwsgs_get_auth_level(struct per_vhost_data__gs *vhd, - const char *username) +lwsgs_get_auth_level(struct per_vhost_data__gs *vhd, const char *username) { struct lwsgs_user u; int n = 0; /* we are logged in as some kind of user */ if (username[0]) { - n |= LWSGS_AUTH_LOGGED_IN; /* we are logged in as admin */ if (!strcmp(username, vhd->admin_user)) - n |= LWSGS_AUTH_VERIFIED | LWSGS_AUTH_ADMIN; /* automatically verified */ + /* automatically verified */ + n |= LWSGS_AUTH_VERIFIED | LWSGS_AUTH_ADMIN; } if (!lwsgs_lookup_user(vhd, username, &u)) { if ((u.verified & 0xff) == LWSGS_VERIFIED_ACCEPTED) - n |= LWSGS_AUTH_VERIFIED; + n |= LWSGS_AUTH_LOGGED_IN | LWSGS_AUTH_VERIFIED; if (u.last_forgot_validated > (time_t)lws_now_secs() - 300) n |= LWSGS_AUTH_FORGOT_FLOW; @@ -380,24 +385,31 @@ int lwsgs_check_credentials(struct per_vhost_data__gs *vhd, const char *username, const char *password) { - unsigned char buffer[300]; + struct lws_genhash_ctx hash_ctx; lwsgw_hash_bin hash_bin; struct lwsgs_user u; lwsgw_hash hash; - int n; if (lwsgs_lookup_user(vhd, username, &u)) return -1; lwsl_info("user %s found, salt '%s'\n", username, u.pwsalt.id); - /* [password in ascii][salt] */ - n = lws_snprintf((char *)buffer, sizeof(buffer) - 1, - "%s-%s-%s", password, vhd->confounder, u.pwsalt.id); + /* sha256sum of password + salt */ - /* sha1sum of password + salt */ - lws_SHA1(buffer, n, hash_bin.bin); - sha1_to_lwsgw_hash(&hash_bin.bin[0], &hash); + if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256) || + lws_genhash_update(&hash_ctx, password, strlen(password)) || + lws_genhash_update(&hash_ctx, "-", 1) || + lws_genhash_update(&hash_ctx, vhd->confounder, strlen(vhd->confounder)) || + lws_genhash_update(&hash_ctx, "-", 1) || + lws_genhash_update(&hash_ctx, u.pwsalt.id, strlen(u.pwsalt.id)) || + lws_genhash_destroy(&hash_ctx, hash_bin.bin)) { + lws_genhash_destroy(&hash_ctx, NULL); + + return 1; + } + + sha256_to_lwsgw_hash(&hash_bin.bin[0], &hash); return !!strcmp(hash.id, u.pwhash.id); } @@ -408,11 +420,9 @@ int lwsgs_hash_password(struct per_vhost_data__gs *vhd, const char *password, struct lwsgs_user *u) { + unsigned char sid_rand[32]; + struct lws_genhash_ctx hash_ctx; lwsgw_hash_bin hash_bin; - lwsgw_hash hash; - unsigned char sid_rand[20]; - unsigned char buffer[150]; - int n; /* create a random salt as big as the hash */ @@ -422,23 +432,31 @@ lwsgs_hash_password(struct per_vhost_data__gs *vhd, lwsl_err("Problem getting random for salt\n"); return 1; } - sha1_to_lwsgw_hash(sid_rand, &u->pwsalt); - + sha256_to_lwsgw_hash(sid_rand, &u->pwsalt); +/* if (lws_get_random(vhd->context, sid_rand, sizeof(sid_rand)) != sizeof(sid_rand)) { lwsl_err("Problem getting random for token\n"); return 1; } - sha1_to_lwsgw_hash(sid_rand, &hash); + sha256_to_lwsgw_hash(sid_rand, &hash); +*/ + /* sha256sum of password + salt */ - /* [password in ascii][salt] */ - n = lws_snprintf((char *)buffer, sizeof(buffer) - 1, - "%s-%s-%s", password, vhd->confounder, u->pwsalt.id); + if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256) || + lws_genhash_update(&hash_ctx, password, strlen(password)) || + lws_genhash_update(&hash_ctx, "-", 1) || + lws_genhash_update(&hash_ctx, vhd->confounder, strlen(vhd->confounder)) || + lws_genhash_update(&hash_ctx, "-", 1) || + lws_genhash_update(&hash_ctx, u->pwsalt.id, strlen(u->pwsalt.id)) || + lws_genhash_destroy(&hash_ctx, hash_bin.bin)) { + lws_genhash_destroy(&hash_ctx, NULL); - /* sha1sum of password + salt */ - lws_SHA1(buffer, n, hash_bin.bin); - sha1_to_lwsgw_hash(&hash_bin.bin[0], &u->pwhash); + return 1; + } + + sha256_to_lwsgw_hash(&hash_bin.bin[0], &u->pwhash); return 0; } diff --git a/plugins/protocol_post_demo.c b/plugins/protocol_post_demo.c index a2f8e7cc0..02503c3ae 100644 --- a/plugins/protocol_post_demo.c +++ b/plugins/protocol_post_demo.c @@ -225,8 +225,7 @@ callback_post_demo(struct lws *wsi, enum lws_callback_reasons reason, /* first send the headers ... */ n = lws_write(wsi, start, lws_ptr_diff(p, start), - LWS_WRITE_HTTP_HEADERS | - LWS_WRITE_H2_STREAM_END); + LWS_WRITE_HTTP_HEADERS); if (n < 0) goto bail; diff --git a/scripts/autobahn-test-server.sh b/scripts/autobahn-test-server.sh index 4f99e8c51..0a445f4b4 100755 --- a/scripts/autobahn-test-server.sh +++ b/scripts/autobahn-test-server.sh @@ -29,13 +29,8 @@ killall wstest 2>/dev/null # # 2.10 / 2.11: There is no requirement to handle multiple PING / PONG -# in flight in RFC6455. lws doesn't waste memory on it -# since it is useless. -# -# 12.3.1 / 12.3.2 -# 12.4.* / 12.5.*: Autobahn has been broken for these tests since Aug 2017 -# https://github.com/crossbario/autobahn-testsuite/issues/71 - +# in flight on a single connection in RFC6455. lws doesn't +# waste memory on supporting it since it is useless. cat << EOF >fuzzingclient.json { @@ -45,7 +40,7 @@ cat << EOF >fuzzingclient.json "url": "ws://127.0.0.1:9001" } ], - "cases": ["*"], + "cases": [ "12.2.13" ], "exclude-cases": ["2.10", "2.11" ], "exclude-agent-cases": {} }