From 7a2fc442b61cb08a4ffbcdee0912fd56941e7d46 Mon Sep 17 00:00:00 2001
From: Andy Green <andy@warmcat.com>
Date: Thu, 19 May 2016 15:28:31 +0800
Subject: [PATCH] protocol generic sessions

Signed-off-by: Andy Green <andy@warmcat.com>
---
 CMakeLists.txt                                | 122 ++-
 README.generic-sessions.md                    | 383 ++++++++
 appveyor.yml                                  |   5 +-
 lib/context.c                                 |  47 +-
 lib/lejp-conf.c                               |  36 +-
 lib/libwebsockets.c                           |  68 +-
 lib/libwebsockets.h                           |  47 +
 lib/output.c                                  |  49 +-
 lib/private-libwebsockets.h                   |   2 +
 lib/server.c                                  | 197 +++-
 .../generic-sessions/assets/admin-login.html  |   5 +
 .../generic-sessions/assets/failed-login.html |   3 +
 plugins/generic-sessions/assets/index.html    |  35 +
 .../generic-sessions/assets/lwsgs-logo.png    | Bin 0 -> 9729 bytes
 plugins/generic-sessions/assets/lwsgs.js      | 476 +++++++++
 plugins/generic-sessions/assets/md5.min.js    |   2 +
 .../assets/post-forgot-fail.html              |   5 +
 .../assets/post-forgot-ok.html                |   6 +
 .../assets/post-register-fail.html            |   1 +
 .../assets/post-register-ok.html              |  27 +
 .../assets/post-verify-fail.html              |  20 +
 .../assets/post-verify-ok.html                |  25 +
 plugins/generic-sessions/assets/seats.jpg     | Bin 0 -> 122754 bytes
 .../assets/sent-forgot-fail.html              |   5 +
 .../assets/sent-forgot-ok.html                |   4 +
 .../assets/successful-login.html              |   4 +
 plugins/generic-sessions/handlers.c           | 598 ++++++++++++
 plugins/generic-sessions/private-lwsgs.h      | 161 ++++
 .../protocol_generic_sessions.c               | 901 ++++++++++++++++++
 plugins/generic-sessions/utils.c              | 450 +++++++++
 plugins/protocol_lws_status.c                 |   1 +
 plugins/protocol_post_demo.c                  |   9 +-
 test-server/test-server-v2.0.c                |   6 +
 test-server/test-server.h                     |   2 +-
 34 files changed, 3598 insertions(+), 104 deletions(-)
 create mode 100644 README.generic-sessions.md
 create mode 100644 plugins/generic-sessions/assets/admin-login.html
 create mode 100644 plugins/generic-sessions/assets/failed-login.html
 create mode 100644 plugins/generic-sessions/assets/index.html
 create mode 100644 plugins/generic-sessions/assets/lwsgs-logo.png
 create mode 100644 plugins/generic-sessions/assets/lwsgs.js
 create mode 100644 plugins/generic-sessions/assets/md5.min.js
 create mode 100644 plugins/generic-sessions/assets/post-forgot-fail.html
 create mode 100644 plugins/generic-sessions/assets/post-forgot-ok.html
 create mode 100644 plugins/generic-sessions/assets/post-register-fail.html
 create mode 100644 plugins/generic-sessions/assets/post-register-ok.html
 create mode 100644 plugins/generic-sessions/assets/post-verify-fail.html
 create mode 100644 plugins/generic-sessions/assets/post-verify-ok.html
 create mode 100644 plugins/generic-sessions/assets/seats.jpg
 create mode 100644 plugins/generic-sessions/assets/sent-forgot-fail.html
 create mode 100644 plugins/generic-sessions/assets/sent-forgot-ok.html
 create mode 100644 plugins/generic-sessions/assets/successful-login.html
 create mode 100644 plugins/generic-sessions/handlers.c
 create mode 100644 plugins/generic-sessions/private-lwsgs.h
 create mode 100644 plugins/generic-sessions/protocol_generic_sessions.c
 create mode 100644 plugins/generic-sessions/utils.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index eceddacd..33642ab1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -99,8 +99,9 @@ option(LWS_WITH_ACCESS_LOG "Support generating Apache-compatible access logs" OF
 option(LWS_WITH_SERVER_STATUS "Support json + jscript server monitoring" OFF)
 option(LWS_WITH_LEJP "With the Lightweight JSON Parser" OFF)
 option(LWS_WITH_LEJP_CONF "With LEJP configuration parser as used by lwsws" OFF)
+option(LWS_WITH_GENERIC_SESSIONS "With the Generic Sessions plugin" OFF)
+option(LWS_WITH_SQLITE3 "Require SQLITE3 support" OFF)
 option(LWS_WITH_SMTP "Provide SMTP support" OFF)
-option(LWS_WITH_STATEFUL_URLDECODE "Provide stateful URLDECODE apis" OFF)
 
 if (LWS_WITH_LWSWS)
  message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV")
@@ -112,10 +113,6 @@ if (LWS_WITH_LWSWS)
  set(LWS_WITH_LEJP_CONF 1)
 endif()
 
-if (LWS_WITH_PLUGINS)
- set(LWS_WITH_STATEFUL_URLDECODE 1)
-endif()
-
 if (LWS_WITH_PLUGINS AND NOT LWS_WITH_LIBUV)
 message(STATUS "LWS_WITH_PLUGINS --> Enabling LWS_WITH_LIBUV")
  set(LWS_WITH_LIBUV 1)
@@ -126,6 +123,16 @@ message(STATUS "LWS_WITH_SMTP --> Enabling LWS_WITH_LIBUV")
  set(LWS_WITH_LIBUV 1)
 endif()
 
+if (LWS_WITH_GENERIC_SESSIONS)
+ set(LWS_WITH_SQLITE3 1)
+ set(LWS_WITH_SMTP 1)
+endif()
+
+if (LWS_WITH_SMTP AND NOT LWS_WITH_LIBUV)
+message(STATUS "LWS_WITH_SMTP --> Enabling LWS_WITH_LIBUV")
+ set(LWS_WITH_LIBUV 1)
+endif()
+
 if (DEFINED YOTTA_WEBSOCKETS_VERSION_STRING)
 
 set(LWS_WITH_SHARED OFF)
@@ -198,6 +205,9 @@ set( CACHE PATH "Path to the libev library")
 set(LWS_LIBEV_INCLUDE_DIRS CACHE PATH "Path to the libev include directory")
 set(LWS_LIBUV_LIBRARIES CACHE PATH "Path to the libuv library")
 set(LWS_LIBUV_INCLUDE_DIRS CACHE PATH "Path to the libuv include directory")
+set(LWS_SQLITE3_LIBRARIES CACHE PATH "Path to the libuv library")
+set(LWS_SQLITE3_INCLUDE_DIRS CACHE PATH "Path to the libuv include directory")
+
 
 if (NOT LWS_WITH_SSL)
 	set(LWS_WITHOUT_BUILTIN_SHA1 OFF)
@@ -285,6 +295,15 @@ if (LWS_WITH_LIBUV)
 	endif()
 endif()
 
+if (LWS_WITH_SQLITE3)
+	if ("${LWS_SQLITE3_LIBRARIES}" STREQUAL "" OR "${LWS_SQLITE3_INCLUDE_DIRS}" STREQUAL "")
+	else()
+		set(SQLITE3_LIBRARIES ${LWS_SQLITE3_LIBRARIES})
+		set(SQLITE3_INCLUDE_DIRS ${LWS_SQLITE3_INCLUDE_DIRS})
+		set(SQLITE3_FOUND 1)
+	endif()
+endif()
+
 
 # FIXME: This must be runtime-only option.
 # The base dir where the test-apps look for the SSL certs.
@@ -612,6 +631,17 @@ endif()
 if (WIN32)
 	set(WIN32_HELPERS_PATH win32port/win32helpers)
 	include_directories(${WIN32_HELPERS_PATH})
+
+		if (WIN32)
+			list(APPEND SOURCES
+				${WIN32_HELPERS_PATH}/gettimeofday.c
+			)
+
+			list(APPEND HDR_PRIVATE
+				${WIN32_HELPERS_PATH}/gettimeofday.h
+			)
+		endif(WIN32)
+
 else()
 	# Unix.
 	if (NOT LWS_WITHOUT_DAEMONIZE)
@@ -870,6 +900,22 @@ if (LWS_WITH_LIBUV)
 	include_directories("${LIBUV_INCLUDE_DIRS}")
 	list(APPEND LIB_LIST ${LIBUV_LIBRARIES})
 endif()
+
+if (LWS_WITH_SQLITE3)
+	if (NOT SQLITE3_FOUND)
+		find_path(SQLITE3_INCLUDE_DIRS NAMES sqlite3.h)
+		find_library(SQLITE3_LIBRARIES NAMES sqlite3)
+		if(SQLITE3_INCLUDE_DIRS AND SQLITE3_LIBRARIES)
+			set(SQLITE3_FOUND 1)
+		endif()
+	endif()
+	message("sqlite3 include dir: ${SQLITE3_INCLUDE_DIRS}")
+	message("sqlite3 libraries: ${SQLITE3_LIBRARIES}")
+	include_directories("${SQLITE3_INCLUDE_DIRS}")
+	list(APPEND LIB_LIST ${SQLITE3_LIBRARIES})
+endif()
+
+
 if (LWS_WITH_HTTP_PROXY)
 	find_library(LIBHUBBUB_LIBRARIES NAMES libhubbub)
 	list(APPEND LIB_LIST ${LIBHUBBUB_LIBRARIES} )
@@ -1204,10 +1250,19 @@ if (NOT LWS_WITHOUT_TESTAPPS)
 	
 	
 	if (LWS_WITH_PLUGINS AND LWS_WITH_SHARED)
-		macro(create_plugin PLUGIN_NAME MAIN_SRC)
+		macro(create_plugin PLUGIN_NAME MAIN_SRC S2 S3)
 
 		set(PLUGIN_SRCS ${MAIN_SRC})
 
+		if ("${S2}" STREQUAL "")
+		else()
+			list(APPEND PLUGIN_SRCS ${S2})
+		endif()
+		if ("${S3}" STREQUAL "")
+		else()
+			list(APPEND PLUGIN_SRCS ${S3})
+		endif()
+
 		if (WIN32)
 			list(APPEND PLUGIN_SRCS
 				${WIN32_HELPERS_PATH}/getopt.c
@@ -1239,27 +1294,42 @@ if (NOT LWS_WITHOUT_TESTAPPS)
 #			OUTPUT_NAME ${PLUGIN_NAME})
 
 		list(APPEND PLUGINS_LIST ${PLUGIN_NAME})
+
 		endmacro()
 		
 
 		create_plugin(protocol_dumb_increment
-			      "plugins/protocol_dumb_increment.c")
+			      "plugins/protocol_dumb_increment.c" "" "")
 		create_plugin(protocol_lws_mirror
-			      "plugins/protocol_lws_mirror.c")
+			      "plugins/protocol_lws_mirror.c" "" "")
 		create_plugin(protocol_lws_status
-			      "plugins/protocol_lws_status.c")
+			      "plugins/protocol_lws_status.c" "" "")
 		create_plugin(protocol_post_demo
-			      "plugins/protocol_post_demo.c")
+			      "plugins/protocol_post_demo.c" "" "")
 if (LWS_WITH_SERVER_STATUS)
 		create_plugin(protocol_lws_server_status
-			      "plugins/protocol_lws_server_status.c")
+			      "plugins/protocol_lws_server_status.c" "" "")
 endif()
 
 if (NOT LWS_WITHOUT_CLIENT)
 		create_plugin(protocol_client_loopback_test
-                              "plugins/protocol_client_loopback_test.c")
+                              "plugins/protocol_client_loopback_test.c" "" "")
 endif(NOT LWS_WITHOUT_CLIENT)
 
+if (LWS_WITH_GENERIC_SESSIONS)
+	create_plugin(protocol_generic_sessions
+                      "plugins/generic-sessions/protocol_generic_sessions.c"
+		      "plugins/generic-sessions/utils.c"
+		      "plugins/generic-sessions/handlers.c")
+
+	if (WIN32)
+		target_link_libraries(protocol_generic_sessions ${LWS_SQLITE3_LIBRARIES})
+	else()
+		target_link_libraries(protocol_generic_sessions sqlite3 )
+	endif(WIN32)
+endif(LWS_WITH_GENERIC_SESSIONS)
+
+
 	endif(LWS_WITH_PLUGINS AND LWS_WITH_SHARED)
 
 	#
@@ -1460,6 +1530,31 @@ if (LWS_WITH_SERVER_STATUS)
 		DESTINATION share/libwebsockets-test-server/server-status
 			COMPONENT examples)
 endif()
+if (LWS_WITH_GENERIC_SESSIONS)
+	install(FILES
+		      plugins/generic-sessions/assets/lwsgs-logo.png
+		      plugins/generic-sessions/assets/seats.jpg
+		      plugins/generic-sessions/assets/failed-login.html
+		      plugins/generic-sessions/assets/lwsgs.js
+		      plugins/generic-sessions/assets/post-register-fail.html
+		      plugins/generic-sessions/assets/post-register-ok.html
+		      plugins/generic-sessions/assets/post-verify-ok.html
+		      plugins/generic-sessions/assets/post-verify-fail.html
+		      plugins/generic-sessions/assets/sent-forgot-ok.html
+		      plugins/generic-sessions/assets/sent-forgot-fail.html
+		      plugins/generic-sessions/assets/post-forgot-ok.html
+		      plugins/generic-sessions/assets/post-forgot-fail.html
+		      plugins/generic-sessions/assets/index.html
+		DESTINATION share/libwebsockets-test-server/generic-sessions
+			COMPONENT examples)
+	install(FILES plugins/generic-sessions/assets/successful-login.html 
+		DESTINATION share/libwebsockets-test-server/generic-sessions/needauth
+			COMPONENT examples)
+	install(FILES plugins/generic-sessions/assets/admin-login.html
+		DESTINATION share/libwebsockets-test-server/generic-sessions/needadmin
+			COMPONENT examples)
+endif()
+
 endif()
 
 # Install the LibwebsocketsConfig.cmake and LibwebsocketsConfigVersion.cmake
@@ -1531,7 +1626,8 @@ message(" LWS_WITH_SERVER_STATUS = ${LWS_WITH_SERVER_STATUS}")
 message(" LWS_WITH_LEJP = ${LWS_WITH_LEJP}")
 message(" LWS_WITH_LEJP_CONF = ${LWS_WITH_LEJP_CONF}")
 message(" LWS_WITH_SMTP = ${LWS_WITH_SMTP}")
-message(" LWS_WITH_STATEFUL_URLDECODE = ${LWS_WITH_STATEFUL_URLDECODE}")
+message(" LWS_WITH_GENERIC_SESSIONS = ${LWS_WITH_GENERIC_SESSIONS}")
+
 
 message("---------------------------------------------------------------------")
 
diff --git a/README.generic-sessions.md b/README.generic-sessions.md
new file mode 100644
index 00000000..dab28734
--- /dev/null
+++ b/README.generic-sessions.md
@@ -0,0 +1,383 @@
+Generic Sessions Plugin
+-----------------------
+
+Enabling for build
+------------------
+
+Enable at CMake with -DLWS_WITH_GENERIC_SESSIONS=1
+
+This also needs sqlite3 (libsqlite3-dev or similar package)
+
+
+Introduction
+------------
+
+The generic-sessions protocol plugin provides cookie-based login
+authentication for lws web and ws connections.
+
+The plugin handles everything about generic account registration,
+email verification, lost password, account deletion, and other generic account
+management.
+
+Other code, in another eg, ws protocol handler, only needs very high-level
+state information from generic-sessions, ie, which user the client is
+authenticated as.  Everything underneath is managed in generic-sessions.
+
+
+ - random 20-byte session id managed in a cookie
+
+ - all information related to the session held at the server, nothing managed clientside
+
+ - sqlite3 used at the server to manage active sessions and users
+
+ - defaults to creating anonymous sessions with no user associated
+
+ - admin account (with user-selectable username) is defined in config with a SHA-1 of the password; rest of the accounts are in sqlite3
+ 
+  - user account passwords stored as salted SHA-1 with additional confounder
+  only stored in the JSON config, not the database 
+
+ - login, logout, register account + email verification built-in with examples
+
+ - in a mount, some file suffixes (ie, .js) can be associated with a protocol for the purposes of rewriting symbolnames.  These are read-only copies of logged-in server state.
+
+ - When your page fetches .js or other rewritten files from that mount, "$lwsgs_user" and so on are rewritten on the fly using chunked transfer encoding
+
+ - Eliminates server-side scripting with a few rewritten symbols and
+ javascript on client side
+
+ - 32-bit bitfield for authentication sectoring, mounts can provide a mask on the loggin-in session's associated server-side bitfield that must be set for access.
+
+ - No code (just config) required for, eg, private URL namespace that requires login to access. 
+ 
+
+Integration to HTML
+-------------------
+
+Only three steps are needed to integrate lwsgs in your HTML.
+
+1) lwsgs HTML UI is bundled with the javascript it uses in `lwsgs.js`, so
+import that script file in your head section
+
+2) define an empty div of id "lwsgs" somewhere
+
+3) Call lwsgs_initial() in your page
+
+That's it.  An example is below
+
+
+```
+<html>
+ <head>
+  <script src="lwsgs.js"></script>
+  <style>
+     .body { font-size: 12 }
+     .gstitle { font-size: 18 }
+  </style>
+  </head>
+  <body style="background-image:url(seats.jpg)">
+    <table style="width:100%;transition: max-height 2s;">
+     <tr>
+      <td style="vertical-align:top;text-align:left;width=200px">
+       <img src="lwsgs-logo.png">
+      </td>
+      <td style="vertical-align:top;float:right">
+	<div id=lwsgs style="text-align:right;background-color: rgba(255, 255, 255, 0.8);"></div>
+      </td>
+     </tr>
+    </table>
+   </form>
+   
+   <script>lwsgs_initial();</script>
+
+ </body>
+</html>
+```
+
+Overall Flow
+------------
+
+When the protocol is initialized, it gets per-vhost information from the config, such
+as where the sqlite3 databases are to be stored.  The admin username and sha-1 of the
+admin password are also taken from here.
+
+In the mounts using protocol-generic-sessions, a cookie is maintained against any requests; if no cookie was active on the initial request a new session is
+created with no attached user.
+
+So there should always be an active session after any transactions with the server.
+
+In the example html going to the mount /lwsgs loads a login / register page as the default.
+
+The <form> in the login page contains 'next url' hidden inputs that let the html 'program' where the form handler will go after a successful admin login, a successful user login and a failed login.
+
+After a successful login, the sqlite record at the server for the current session is updated to have the logged-in username associated with it. 
+
+
+
+Configuration
+-------------
+
+"auth-mask" defines the autorization sector bits that must be enabled on the session to gain access.
+
+"auth-mask" 0 is the default.
+
+  - b0 is set if you are logged in as a user at all.
+  - b1 is set if you are logged in with the user configured to be admin
+  - b2 is set if the account has been verified (the account configured for admin is always verified)
+
+```
+      {
+        # things in here can always be served
+        "mountpoint": "/lwsgs",
+        "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions",
+        "origin": "callback://protocol-lws-messageboard",
+        "default": "generic-sessions-login-example.html",
+        "auth-mask": "0",
+        "interpret": {
+                ".js": "protocol-lws-messageboard"
+        }
+       }, {
+        # things in here can only be served if logged in as a user
+        "mountpoint": "/lwsgs/needauth",
+        "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions/needauth",
+        "origin": "callback://protocol-lws-messageboard",
+        "default": "generic-sessions-login-example.html",
+        "auth-mask": "5", # logged in as a verified user
+        "interpret": {
+                ".js": "protocol-lws-messageboard"
+        }
+       }, {
+        # things in here can only be served if logged in as admin
+        "mountpoint": "/lwsgs/needadmin",
+        "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions/needadmin",
+        "origin": "callback://protocol-lws-messageboard",
+        "default": "generic-sessions-login-example.html",
+        "auth-mask": "7", # b2 = verified (by email / or admin), b1 = admin, b0 = logged in with any user name
+        "interpret": {
+                ".js": "protocol-lws-messageboard"
+        }
+       }
+```
+
+Note that the name of the real application protocol that uses generic-sessions
+is used, not generic-sessions itself. 
+
+The vhost configures the storage dir, admin credentials and session cookie lifetimes:
+
+```
+     "ws-protocols": [{
+       "protocol-generic-sessions": {
+         "status": "ok",
+         "admin-user": "admin",
+
+# create the pw hash like this (for the example pw, "jipdocesExunt" )
+# $ echo -n "jipdocesExunt" | sha1sum
+# 046ce9a9cca769e85798133be06ef30c9c0122c9 -
+#
+# Obviously ** change this password hash to a secret one before deploying **
+#
+         "admin-password-sha1": "046ce9a9cca769e85798133be06ef30c9c0122c9",
+         "session-db": "/var/www/sessions/lws.sqlite3",
+         "timeout-idle-secs": "600",
+	 "timeout-anon-idle-secs": "1200",
+         "timeout-absolute-secs": "6000",
+# the confounder is part of the salted password hashes.  If this config
+# file is in a 0700 root:root dir, an attacker with apache credentials
+# will have to get the confounder out of the process image to even try
+# to guess the password hashes.
+         "confounder": "Change to <=31 chars of junk",
+
+         "email-from": "noreply@example.com",
+         "email-smtp-ip": "127.0.0.1",
+         "email-expire": "3600",
+         "email-helo": "myhost.com",
+         "email-contact-person": "Set Me <real-person@email.com>",
+         "email-confirm-url-base": "http://localhost:7681/lwsgs"
+       }
+```
+
+The email- related settings control generation of automatic emails for
+registration and forgotten password.
+
+ - `email-from`: The email address automatic emails are sent from
+
+ - `email-smtp-ip`: Normally 127.0.0.1, if you have a suitable server on port
+   25 on your lan you can use this instead here.
+
+ - `email-expire`: Seconds that links sent in email will work before being
+   deleted
+
+ - `email-helo`: HELO to use when communicating with your SMTP server
+
+ - `email-contact-person`: mentioned in the automatic emails as a human who can
+   answer questions
+
+ - `email-confirm-url-base`: the URL to start links with in the emails, so the
+   recipient can get back to the web server
+   
+The real protocol that makes use of generic-sessions must also be listed and
+any configuration it needs given
+
+```
+       "protocol-lws-messageboard": {
+         "status": "ok",
+         "message-db": "/var/www/sessions/messageboard.sqlite3"
+       },
+```
+Notice the real application uses his own sqlite db, no details about how
+generic-sessions works or how it stores data are available to it.
+
+
+Password Confounder
+-------------------
+
+You can also define a per-vhost confounder shown in the example above, used
+when aggregating the password with the salt when it is hashed.  Any attacker
+will also need to get the confounder along with the database, which you can
+make harder by making the config dir only eneterable / readable by root.
+
+
+Preparing the db directory
+--------------------------
+
+You will have to prepare the db directory so it's suitable for the lwsws user to use,
+that usually means apache, eg
+
+```
+# mkdir -p /var/www/sessions
+# chown root:apache /var/www/sessions
+# chmod 770 /var/www/sessions
+```
+
+Email configuration
+-------------------
+
+lwsgs will can send emails by talking to an SMTP server on localhost:25.  That
+will usually be sendmail or postfix, you should confirm that works first by
+itself using the `mail` application to send on it.
+
+lwsgs has been tested on stock Fedora sendmail and postfix.
+
+
+Integration with another protocol
+---------------------------------
+
+lwsgs is designed to provide sessions and accounts in a standalone and generic way.
+
+But it's not useful by itself, there will always be the actual application who wants
+to make use of generic-sessions features.
+
+The basic approach is the 'real' protocol handler (usually a plugin itself)
+subclasses the generic-sessions plugin and calls through to it by default.
+
+The "real" protocol handler entirely deals with ws-related stuff itself, since
+generic-sessions does not use ws.  But for
+
+ - LWS_CALLBACK_HTTP
+ - LWS_CALLBACK_HTTP_BODY
+ - LWS_CALLBACK_HTTP_BODY_COMPLETION
+ - LWS_CALLBACK_HTTP_DROP_PROTOCOL
+ 
+the "real" protocol handler checks if it recognizes the activity (eg, his own
+POST form URL) and if not, passes stuff through to the generic-sessions protocol callback to handle it.  To simplify matters the real protocol can just pass
+through any unhandled messages to generic-sessions.
+
+The "real" protocol can get a pointer to generic-sessions protocol on the
+same vhost using
+
+```
+	vhd->gsp = lws_vhost_name_to_protocol(vhd->vh, "protocol-generic-sessions");
+```
+
+The "real" protocol must also arrange generic-sessions per_session_data in his
+own per-session allocation.  To allow keeping generic-sessions opaque, the
+real protocol must allocate that space at runtime, using the pss size
+the generic-sessions protocol struct exposes
+
+```
+struct per_session_data__myapp {
+	void *pss_gs;
+...
+
+	pss->pss_gs = malloc(vhd->gsp->per_session_data_size);
+```
+
+The allocation reserved for generic-sessions is then used as user_space when
+the real protocol calls through to the generic-sessions callback
+
+```
+	vhd->gsp->callback(wsi, reason, &pss->pss_gs, in, len);
+```
+
+In that way the "real" protocol can subclass generic-sessions functionality.
+
+
+To ease management of these secondary allocations, there are callbacks that
+occur when a wsi binds to a protocol and when the binding is dropped.  These
+should be used to malloc and free and kind of per-connection
+secondary allocations.
+
+
+```
+	case LWS_CALLBACK_HTTP_BIND_PROTOCOL:
+		if (!pss || pss->pss_gs)
+			break;
+
+		pss->pss_gs = malloc(vhd->gsp->per_session_data_size);
+		if (!pss->pss_gs)
+			return -1;
+
+		memset(pss->pss_gs, 0, vhd->gsp->per_session_data_size);
+		break;
+
+	case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
+		if (vhd->gsp->callback(wsi, reason, pss ? pss->pss_gs : NULL, in, len))
+			return -1;
+
+		if (pss->pss_gs) {
+			free(pss->pss_gs);
+			pss->pss_gs = NULL;
+		}
+		break;
+```
+
+
+Getting session-specific information from another protocol
+----------------------------------------------------------
+
+At least at the time when someone tries to upgrade an http(s) connection to
+ws(s) with your real protocol, it is necessary to confirm the cookie the http(s)
+connection has with generic-sessions and find out his username and other info.
+
+Generic sessions lets another protocol check it again by calling his callback,
+and lws itself provides a generic session info struct to pass the related data
+
+```
+struct lws_session_info {
+	char username[32];
+	char email[100];
+	char ip[72];
+	unsigned int mask;
+	char session[42];
+};
+```
+
+```
+	struct lws_session_info sinfo;
+	...
+	vhd->gsp->callback(wsi, LWS_CALLBACK_SESSION_INFO,
+				   &pss->pss_gs, &sinfo, 0);
+```
+
+After the call to generic-sessions, the results can be
+
+ -  all the strings will be zero-length and .mask zero, there is no usable cookie
+ 
+  - only .ip and .session are set: the cookie is OK but no user logged in
+  
+  - all the strings contain information about the logged-in user
+
+the real protocol can use this to reject attempts to open ws connections from
+http connections that are not authenticated; afterwards there's no need to
+check the ws connection auth status again.
+
diff --git a/appveyor.yml b/appveyor.yml
index b5cb9afc..4bbc0f1a 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,7 +1,7 @@
 environment:
   matrix:
     - LWS_METHOD: lwsws
-      CMAKE_ARGS: -DLWS_WITH_LWSWS=1 -DLIBUV_INCLUDE_DIRS=C:\assets\libuv\include -DLIBUV_LIBRARIES=C:\assets\libuv\libuv.lib
+      CMAKE_ARGS: -DLWS_WITH_LWSWS=1 -DSQLITE3_INCLUDE_DIRS=C:\assets\sqlite3 -DSQLITE3_LIBRARIES=C:\assets\sqlite3\sqlite3.lib -DLIBUV_INCLUDE_DIRS=C:\assets\libuv\include -DLIBUV_LIBRARIES=C:\assets\libuv\libuv.lib
 
     - LWS_METHOD: default
 
@@ -26,6 +26,9 @@ install:
   - Win32OpenSSL-1_0_2h.exe /silent /verysilent /sp- /suppressmsgboxes
   - appveyor DownloadFile https://libwebsockets.org:444/nsis-3.0rc1-setup.exe
   - cmd /c start /wait nsis-3.0rc1-setup.exe /S /D=C:\nsis
+  - appveyor DownloadFile https://libwebsockets.org:444/sqlite-dll-win32-x86-3130000.zip
+  - mkdir c:\assets\sqlite3
+  - 7z x -oc:\assets\sqlite3 sqlite-dll-win32-x86-3130000.zip
   - SET PATH=C:\Program Files\NSIS\;C:\Program Files (x86)\NSIS\;c:\nsis;%PATH%
 build:
 
diff --git a/lib/context.c b/lib/context.c
index 0d3a41c1..d3c22d6b 100644
--- a/lib/context.c
+++ b/lib/context.c
@@ -67,8 +67,15 @@ lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, const struct lws_protocols
 	while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
 		n++;
 
-	if (n == vhost->count_protocols)
-		return NULL;
+	if (n == vhost->count_protocols) {
+		n = 0;
+		while (n < vhost->count_protocols &&
+		       strcmp(vhost->protocols[n].name, prot->name))
+			n++;
+
+		if (n == vhost->count_protocols)
+			return NULL;
+	}
 
 	vhost->protocol_vh_privs[n] = lws_zalloc(size);
 	return vhost->protocol_vh_privs[n];
@@ -86,8 +93,15 @@ lws_protocol_vh_priv_get(struct lws_vhost *vhost, const struct lws_protocols *pr
 		n++;
 
 	if (n == vhost->count_protocols) {
-		lwsl_err("%s: unknown protocol %p\n", __func__, prot);
-		return NULL;
+		n = 0;
+		while (n < vhost->count_protocols &&
+		       strcmp(vhost->protocols[n].name, prot->name))
+			n++;
+
+		if (n == vhost->count_protocols) {
+			lwsl_err("%s: unknown protocol %p\n", __func__, prot);
+			return NULL;
+		}
 	}
 
 	return vhost->protocol_vh_privs[n];
@@ -165,15 +179,17 @@ lws_protocol_init(struct lws_context *context)
 			 * NOTE the wsi is all zeros except for the context, vh and
 			 * protocol ptrs so lws_get_context(wsi) etc can work
 			 */
-			vh->protocols[n].callback(&wsi,
+			if (vh->protocols[n].callback(&wsi,
 				LWS_CALLBACK_PROTOCOL_INIT, NULL,
-				(void *)pvo, 0);
+				(void *)pvo, 0))
+				return 1;
 		}
 
 		vh = vh->vhost_next;
 	}
 
 	context->protocol_init_done = 1;
+	lws_finalize_startup(context);
 
 	return 0;
 }
@@ -287,12 +303,14 @@ lws_create_vhost(struct lws_context *context,
 	struct lws_vhost *vh = lws_zalloc(sizeof(*vh)),
 			 **vh1 = &context->vhost_list;
 	const struct lws_http_mount *mounts;
+	const struct lws_protocol_vhost_options *pvo;
 #ifdef LWS_WITH_PLUGINS
 	struct lws_plugin *plugin = context->plugin_list;
 	struct lws_protocols *lwsp;
-	int m, n, f = !info->pvo;
+	int m, f = !info->pvo;
 #endif
 	char *p;
+	int n;
 
 	if (!vh)
 		return NULL;
@@ -381,6 +399,21 @@ lws_create_vhost(struct lws_context *context,
 		lwsl_notice("   mounting %s%s to %s\n",
 				mount_protocols[mounts->origin_protocol],
 				mounts->origin, mounts->mountpoint);
+
+		/* convert interpreter protocol names to pointers */
+		pvo = mounts->interpret;
+		while (pvo) {
+			for (n = 0; n < vh->count_protocols; n++)
+				if (!strcmp(pvo->value, vh->protocols[n].name)) {
+					((struct lws_protocol_vhost_options *)pvo)->value =
+							(const char *)(long)n;
+					break;
+				}
+			if (n == vh->count_protocols)
+				lwsl_err("ignoring unknown interpret protocol %s\n", pvo->value);
+			pvo = pvo->next;
+		}
+
 		mounts = mounts->mount_next;
 	}
 
diff --git a/lib/lejp-conf.c b/lib/lejp-conf.c
index 1d529a1f..91429a54 100644
--- a/lib/lejp-conf.c
+++ b/lib/lejp-conf.c
@@ -59,7 +59,9 @@ static const char * const paths_vhosts[] = {
 	"vhosts[].access-log",
 	"vhosts[].mounts[].mountpoint",
 	"vhosts[].mounts[].origin",
+	"vhosts[].mounts[].protocol",
 	"vhosts[].mounts[].default",
+	"vhosts[].mounts[].auth-mask",
 	"vhosts[].mounts[].cgi-timeout",
 	"vhosts[].mounts[].cgi-env[].*",
 	"vhosts[].mounts[].cache-max-age",
@@ -67,6 +69,7 @@ static const char * const paths_vhosts[] = {
 	"vhosts[].mounts[].cache-revalidate",
 	"vhosts[].mounts[].cache-intermediaries",
 	"vhosts[].mounts[].extra-mimetypes.*",
+	"vhosts[].mounts[].interpret.*",
 	"vhosts[].ws-protocols[].*.*",
 	"vhosts[].ws-protocols[].*",
 	"vhosts[].ws-protocols[]",
@@ -94,7 +97,9 @@ enum lejp_vhost_paths {
 	LEJPVP_ACCESS_LOG,
 	LEJPVP_MOUNTPOINT,
 	LEJPVP_ORIGIN,
+	LEJPVP_MOUNT_PROTOCOL,
 	LEJPVP_DEFAULT,
+	LEJPVP_DEFAULT_AUTH_MASK,
 	LEJPVP_CGI_TIMEOUT,
 	LEJPVP_CGI_ENV,
 	LEJPVP_MOUNT_CACHE_MAX_AGE,
@@ -102,6 +107,7 @@ enum lejp_vhost_paths {
 	LEJPVP_MOUNT_CACHE_REVALIDATE,
 	LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
 	LEJPVP_MOUNT_EXTRA_MIMETYPES,
+	LEJPVP_MOUNT_INTERPRET,
 	LEJPVP_PROTOCOL_NAME_OPT,
 	LEJPVP_PROTOCOL_NAME,
 	LEJPVP_PROTOCOL,
@@ -154,6 +160,7 @@ struct jpargs {
 
 	struct lws_protocol_vhost_options *pvo;
 	struct lws_protocol_vhost_options *pvo_em;
+	struct lws_protocol_vhost_options *pvo_int;
 	struct lws_http_mount m;
 	const char **plugin_dirs;
 	int count_plugin_dirs;
@@ -363,8 +370,10 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
 		for (n = 0; n < ARRAY_SIZE(mount_protocols); n++)
 			if (!strncmp(a->m.origin, mount_protocols[n],
 			     strlen(mount_protocols[n]))) {
+				lwsl_err("----%s\n", a->m.origin);
 				m->origin_protocol = n;
-				m->origin = a->m.origin + strlen(mount_protocols[n]);
+				m->origin = a->m.origin +
+					    strlen(mount_protocols[n]);
 				break;
 			}
 
@@ -424,11 +433,18 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
 		a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
 		break;
 	case LEJPVP_ORIGIN:
-		a->m.origin = a->p;
+		if (!strncmp(ctx->buf, "callback://", 11))
+			a->m.protocol = a->p + 11;
+
+		if (!a->m.origin)
+			a->m.origin = a->p;
 		break;
 	case LEJPVP_DEFAULT:
 		a->m.def = a->p;
 		break;
+	case LEJPVP_DEFAULT_AUTH_MASK:
+		a->m.auth_mask = atoi(ctx->buf);
+		return 0;
 	case LEJPVP_MOUNT_CACHE_MAX_AGE:
 		a->m.cache_max_age = atoi(ctx->buf);
 		return 0;
@@ -505,6 +521,22 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
 		a->pvo_em->options = NULL;
 		break;
 
+	case LEJPVP_MOUNT_INTERPRET:
+		a->pvo_int = lwsws_align(a);
+		a->p += sizeof(*a->pvo_int);
+
+		n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
+		/* ie, enable this protocol, no options yet */
+		a->pvo_int->next = a->m.interpret;
+		a->m.interpret = a->pvo_int;
+		a->pvo_int->name = a->p;
+		lwsl_notice("  adding interpret %s -> %s\n", a->p,
+			    ctx->buf);
+		a->p += n;
+		a->pvo_int->value = a->p;
+		a->pvo_int->options = NULL;
+		break;
+
 	case LEJPVP_ENABLE_CLIENT_SSL:
 		a->enable_client_ssl = arg_to_bool(ctx->buf);
 		return 0;
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index cac78db5..f8d08fc8 100755
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -1735,39 +1735,6 @@ lws_socket_bind(struct lws_vhost *vhost, int sockfd, int port,
 
 static const char *hex = "0123456789ABCDEF";
 
-static int
-urlencode(const char *in, int inlen, char *out, int outlen)
-{
-	char *start = out, *end = out + outlen;
-
-	while (inlen-- && out < end - 4) {
-		if ((*in >= 'A' && *in <= 'Z') ||
-		    (*in >= 'a' && *in <= 'z') ||
-		    (*in >= '0' && *in <= '9') ||
-		    *in == '-' ||
-		    *in == '_' ||
-		    *in == '.' ||
-		    *in == '~') {
-			*out++ = *in++;
-			continue;
-		}
-		if (*in == ' ') {
-			*out++ = '+';
-			in++;
-			continue;
-		}
-		*out++ = '%';
-		*out++ = hex[(*in) >> 4];
-		*out++ = hex[(*in++) & 15];
-	}
-	*out = '\0';
-
-	if (out >= end - 4)
-		return -1;
-
-	return out - start;
-}
-
 /**
  * lws_sql_purify() - like strncpy but with escaping for sql quotes
  *
@@ -1787,7 +1754,7 @@ lws_sql_purify(char *escaped, const char *string, int len)
 
 	while (*p && len-- > 2) {
 		if (*p == '\'') {
-			*q++ = '\\';
+			*q++ = '\'';
 			*q++ = '\'';
 			len --;
 			p++;
@@ -1964,6 +1931,39 @@ lws_is_cgi(struct lws *wsi) {
 
 #ifdef LWS_WITH_CGI
 
+static int
+urlencode(const char *in, int inlen, char *out, int outlen)
+{
+	char *start = out, *end = out + outlen;
+
+	while (inlen-- && out < end - 4) {
+		if ((*in >= 'A' && *in <= 'Z') ||
+		    (*in >= 'a' && *in <= 'z') ||
+		    (*in >= '0' && *in <= '9') ||
+		    *in == '-' ||
+		    *in == '_' ||
+		    *in == '.' ||
+		    *in == '~') {
+			*out++ = *in++;
+			continue;
+		}
+		if (*in == ' ') {
+			*out++ = '+';
+			in++;
+			continue;
+		}
+		*out++ = '%';
+		*out++ = hex[(*in) >> 4];
+		*out++ = hex[(*in++) & 15];
+	}
+	*out = '\0';
+
+	if (out >= end - 4)
+		return -1;
+
+	return out - start;
+}
+
 static struct lws *
 lws_create_basic_wsi(struct lws_context *context, int tsi)
 {
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index b6ec9bbc..11f6fffc 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -476,6 +476,12 @@ enum lws_callback_reasons {
 	LWS_CALLBACK_COMPLETED_CLIENT_HTTP			= 47,
 	LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ			= 48,
 	LWS_CALLBACK_HTTP_DROP_PROTOCOL				= 49,
+	LWS_CALLBACK_CHECK_ACCESS_RIGHTS			= 50,
+	LWS_CALLBACK_PROCESS_HTML				= 51,
+	LWS_CALLBACK_ADD_HEADERS				= 52,
+	LWS_CALLBACK_SESSION_INFO				= 53,
+
+	LWS_CALLBACK_GS_EVENT					= 54,
 
 	/****** add new things just above ---^ ******/
 
@@ -1338,6 +1344,14 @@ struct lws_protocols {
 	 * This is part of the ABI, don't needlessly break compatibility */
 };
 
+struct lws_session_info {
+	char username[32];
+	char email[100];
+	char ip[72];
+	unsigned int mask;
+	char session[42];
+};
+
 struct lws_process_html_args {
 	char *p;
 	int len;
@@ -1362,6 +1376,33 @@ LWS_VISIBLE LWS_EXTERN int
 lws_chunked_html_process(struct lws_process_html_args *args,
 			 struct lws_process_html_state *s);
 
+/* generic-sessions public api */
+
+#define LWSGS_EMAIL_CONTENT_SIZE 16384
+
+/* SHA-1 binary and hexified versions */
+typedef struct { unsigned char bin[20]; } lwsgw_hash_bin;
+typedef struct { char id[41]; } lwsgw_hash;
+
+enum lwsgs_auth_bits {
+	LWSGS_AUTH_LOGGED_IN = 1,
+	LWSGS_AUTH_ADMIN = 2,
+	LWSGS_AUTH_VERIFIED = 4,
+	LWSGS_AUTH_FORGOT_FLOW = 8,
+};
+
+enum lws_gs_event {
+	LWSGSE_CREATED,
+	LWSGSE_DELETED
+};
+
+struct lws_gs_event_args {
+	enum lws_gs_event event;
+	const char *username;
+	const char *email;
+};
+
+
 enum lws_ext_options_types {
 	EXTARG_NONE,
 	EXTARG_DEC,
@@ -1470,12 +1511,15 @@ struct lws_http_mount {
 	const char *mountpoint; /* mountpoint in http pathspace, eg, "/" */
 	const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */
 	const char *def; /* default target, eg, "index.html" */
+	const char *protocol; /* "protocol-name" to handle mount */
 
 	const struct lws_protocol_vhost_options *cgienv;
 	const struct lws_protocol_vhost_options *extra_mimetypes;
+	const struct lws_protocol_vhost_options *interpret;
 
 	int cgi_timeout;
 	int cache_max_age;
+	unsigned int auth_mask;
 
 	unsigned int cache_reusable:1;
 	unsigned int cache_revalidate:1;
@@ -1737,6 +1781,9 @@ LWS_VISIBLE LWS_EXTERN int
 lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
 			  struct lws_vhost *vhost);
 
+LWS_VISIBLE LWS_EXTERN const struct lws_protocols *
+lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name);
+
 /* deprecated: use lws_get_vhost() */
 LWS_VISIBLE LWS_EXTERN struct lws_vhost *
 lws_vhost_get(struct lws *wsi) LWS_WARN_DEPRECATED;
diff --git a/lib/output.c b/lib/output.c
index f14a4a3f..be0c73c5 100644
--- a/lib/output.c
+++ b/lib/output.c
@@ -568,7 +568,9 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
 {
 	struct lws_context *context = wsi->context;
 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-	unsigned long amount;
+	struct lws_process_html_args args;
+	unsigned long amount, poss;
+	unsigned char *p = pt->serv_buf;
 	int n, m;
 
 	while (wsi->http2_substream || !lws_send_pipe_choked(wsi)) {
@@ -585,31 +587,58 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
 		if (wsi->u.http.filepos == wsi->u.http.filelen)
 			goto all_sent;
 
-		if (lws_plat_file_read(wsi, wsi->u.http.fd, &amount,
-				       pt->serv_buf,
-				       context->pt_serv_buf_size) < 0)
+		poss = context->pt_serv_buf_size;
+
+		if (wsi->sending_chunked) {
+			/* we need to drop the chunk size in here */
+			p += 10;
+			/* allow for the chunk to grow by 128 in translation */
+			poss -= 10 + 128;
+		}
+
+		if (lws_plat_file_read(wsi, wsi->u.http.fd, &amount, p, poss) < 0)
 			return -1; /* caller will close */
 
 		n = (int)amount;
 		if (n) {
 			lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
 					context->timeout_secs);
-			wsi->u.http.filepos += n;
-			m = lws_write(wsi, pt->serv_buf, n,
+
+			if (wsi->sending_chunked) {
+				args.p = (char *)p;
+				args.len = n;
+				args.max_len = poss + 128;
+				args.final = wsi->u.http.filepos + n ==
+					     wsi->u.http.filelen;
+				if (user_callback_handle_rxflow(
+				     wsi->vhost->protocols[(int)wsi->protocol_interpret_idx].callback, wsi,
+				     LWS_CALLBACK_PROCESS_HTML,
+				     wsi->user_space, &args, 0) < 0)
+					return -1;
+				n = args.len;
+				p = (unsigned char *)args.p;
+			}
+
+			m = lws_write(wsi, p, n,
 				      wsi->u.http.filepos == wsi->u.http.filelen ?
-					LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP);
+					LWS_WRITE_HTTP_FINAL :
+					LWS_WRITE_HTTP
+				);
 			if (m < 0)
 				return -1;
 
-			if (m != n)
+			wsi->u.http.filepos += amount;
+			if (m != n) {
 				/* adjust for what was not sent */
 				if (lws_plat_file_seek_cur(wsi, wsi->u.http.fd,
 							   m - n) ==
 							     (unsigned long)-1)
 					return -1;
+			}
 		}
 all_sent:
-		if (!wsi->trunc_len && wsi->u.http.filepos == wsi->u.http.filelen) {
+		if (!wsi->trunc_len &&
+		    wsi->u.http.filepos == wsi->u.http.filelen) {
 			wsi->state = LWSS_HTTP;
 			/* we might be in keepalive, so close it off here */
 			lws_plat_file_close(wsi, wsi->u.http.fd);
@@ -622,11 +651,11 @@ all_sent:
 				     LWS_CALLBACK_HTTP_FILE_COMPLETION,
 				     wsi->user_space, NULL, 0) < 0)
 					return -1;
+
 			return 1;  /* >0 indicates completed */
 		}
 	}
 
-	lwsl_info("choked before able to send whole file (post)\n");
 	lws_callback_on_writable(wsi);
 
 	return 0; /* indicates further processing must be done */
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 5ce64131..12719fcb 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -1257,6 +1257,7 @@ struct lws {
 	unsigned int cache_revalidate:1;
 	unsigned int cache_intermediaries:1;
 	unsigned int favoured_pollin:1;
+	unsigned int sending_chunked:1;
 #ifdef LWS_WITH_ACCESS_LOG
 	unsigned int access_log_pending:1;
 #endif
@@ -1295,6 +1296,7 @@ struct lws {
 	char pending_timeout; /* enum pending_timeout */
 	char pps; /* enum lws_pending_protocol_send */
 	char tsi; /* thread service index we belong to */
+	char protocol_interpret_idx;
 #ifdef LWS_WITH_CGI
 	char cgi_channel; /* which of stdin/out/err */
 	char hdr_state;
diff --git a/lib/server.c b/lib/server.c
index 8aafdbf5..d2398e31 100644
--- a/lib/server.c
+++ b/lib/server.c
@@ -206,6 +206,27 @@ lws_select_vhost(struct lws_context *context, int port, const char *servername)
 	return NULL;
 }
 
+/**
+ * lws_vhost_name_to_protocol() - get vhost's protocol object from its name
+ *
+ * @vh: vhost to search
+ * @name: protocol name
+ *
+ * Returns NULL or a pointer to the vhost's protocol of the requested name
+ */
+
+LWS_VISIBLE LWS_EXTERN const struct lws_protocols *
+lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name)
+{
+	int n;
+
+	for (n = 0; n < vh->count_protocols; n++)
+		if (!strcmp(name, vh->protocols[n].name))
+			return &vh->protocols[n];
+
+	return NULL;
+}
+
 static const char *
 get_mimetype(const char *file, const struct lws_http_mount *m)
 {
@@ -271,11 +292,13 @@ static int
 lws_http_serve(struct lws *wsi, char *uri, const char *origin,
 	       const struct lws_http_mount *m)
 {
+	const struct lws_protocol_vhost_options *pvo = m->interpret;
+	struct lws_process_html_args args;
 	const char *mimetype;
 #ifndef _WIN32_WCE
 	struct stat st;
 #endif
-	char path[256], sym[256];
+	char path[256], sym[512];
 	unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
 	unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
 #if !defined(WIN32)
@@ -342,7 +365,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
 				return -1;
 
 			n = lws_write(wsi, start, p - start,
-					LWS_WRITE_HTTP_HEADERS);
+				      LWS_WRITE_HTTP_HEADERS);
 			if (n != (p - start)) {
 				lwsl_err("_write returned %d from %d\n", n, p - start);
 				return -1;
@@ -363,6 +386,43 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
 		goto bail;
 	}
 
+	wsi->sending_chunked = 0;
+
+	/*
+	 * check if this is in the list of file suffixes to be interpreted by
+	 * a protocol
+	 */
+	while (pvo) {
+		n = strlen(path);
+		if (n > (int)strlen(pvo->name) &&
+		    !strcmp(&path[n - strlen(pvo->name)], pvo->name)) {
+			wsi->sending_chunked = 1;
+			wsi->protocol_interpret_idx = (char)(long)pvo->value;
+			lwsl_info("want %s interpreted by %s\n", path,
+				    wsi->vhost->protocols[(int)(long)(pvo->value)].name);
+			wsi->protocol = &wsi->vhost->protocols[(int)(long)(pvo->value)];
+			if (lws_ensure_user_space(wsi))
+				return -1;
+			break;
+		}
+		pvo = pvo->next;
+	}
+
+	if (m->protocol) {
+		const struct lws_protocols *pp = lws_vhost_name_to_protocol(
+							wsi->vhost, m->protocol);
+
+		wsi->protocol = pp;
+		if (lws_ensure_user_space(wsi))
+			return -1;
+		args.p = (char *)p;
+		args.max_len = end - p;
+		if (pp->callback(wsi, LWS_CALLBACK_ADD_HEADERS,
+					  wsi->user_space, &args, 0))
+			return -1;
+		p = (unsigned char *)args.p;
+	}
+
 	n = lws_serve_http_file(wsi, path, mimetype, (char *)start, p - start);
 
 	if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
@@ -381,6 +441,7 @@ lws_http_action(struct lws *wsi)
 	enum http_connection_type connection_type;
 	enum http_version request_version;
 	char content_length_str[32];
+	struct lws_process_html_args args;
 	const struct lws_http_mount *hm, *hit = NULL;
 	unsigned int n, count = 0;
 	char http_version_str[10];
@@ -409,6 +470,9 @@ lws_http_action(struct lws *wsi)
 #endif
 	};
 #endif
+	static const char * const oprot[] = {
+		"http://", "https://"
+	};
 
 	/* it's not websocket.... shall we accept it as http? */
 
@@ -614,7 +678,8 @@ lws_http_action(struct lws *wsi)
 		    ) {
 			if (hm->origin_protocol == LWSMPRO_CALLBACK ||
 			    ((hm->origin_protocol == LWSMPRO_CGI ||
-			     lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) &&
+			     lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) ||
+			     hm->protocol) &&
 			    hm->mountpoint_len > best)) {
 				best = hm->mountpoint_len;
 				hit = hm;
@@ -628,6 +693,38 @@ lws_http_action(struct lws *wsi)
 		lwsl_debug("*** hit %d %d %s\n", hit->mountpoint_len,
 			   hit->origin_protocol , hit->origin);
 
+		if (hit->protocol) {
+			const struct lws_protocols *pp = lws_vhost_name_to_protocol(
+					wsi->vhost, hit->protocol);
+
+			if (!pp) {
+				lwsl_err("unknown protocol %s\n", hit->protocol);
+				return 1;
+			}
+
+			wsi->protocol = pp;
+			if (lws_ensure_user_space(wsi)) {
+				lwsl_err("Unable to allocate user space\n");
+				return 1;
+			}
+		}
+		lwsl_info("wsi %s protocol '%s'\n", uri_ptr, wsi->protocol->name);
+
+		args.p = uri_ptr;
+		args.len = uri_len;
+		args.max_len = hit->auth_mask;
+		args.final = 0; /* used to signal callback dealt with it */
+
+		n = wsi->protocol->callback(wsi, LWS_CALLBACK_CHECK_ACCESS_RIGHTS,
+					    wsi->user_space, &args, 0);
+		if (n) {
+			lws_return_http_status(wsi, HTTP_STATUS_UNAUTHORIZED,
+					       NULL);
+			goto bail_nuke_ah;
+		}
+		if (args.final) /* callback completely handled it well */
+			return 0;
+
 		/*
 		 * if we have a mountpoint like https://xxx.com/yyy
 		 * there is an implied / at the end for our purposes since
@@ -649,12 +746,12 @@ lws_http_action(struct lws *wsi)
 		    (*s != '/' ||
 		     (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
 		      hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
-		    (hit->origin_protocol != LWSMPRO_CGI && hit->origin_protocol != LWSMPRO_CALLBACK)) {
+		    (hit->origin_protocol != LWSMPRO_CGI &&
+		     hit->origin_protocol != LWSMPRO_CALLBACK //&&
+		     //hit->protocol == NULL
+		     )) {
 			unsigned char *start = pt->serv_buf + LWS_PRE,
 					      *p = start, *end = p + 512;
-			static const char *oprot[] = {
-				"http://", "https://"
-			};
 
 			lwsl_debug("Doing 301 '%s' org %s\n", s, hit->origin);
 
@@ -662,13 +759,14 @@ lws_http_action(struct lws *wsi)
 				goto bail_nuke_ah;
 
 			/* > at start indicates deal with by redirect */
-			if (hit->origin_protocol & 4)
+			if (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
+			    hit->origin_protocol == LWSMPRO_REDIR_HTTPS)
 				n = snprintf((char *)end, 256, "%s%s",
 					    oprot[hit->origin_protocol & 1],
 					    hit->origin);
 			else
 				n = snprintf((char *)end, 256,
-				    "https://%s/%s/",
+				    "%s%s%s/", oprot[lws_is_ssl(wsi)],
 				    lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
 				    uri_ptr);
 
@@ -686,32 +784,36 @@ lws_http_action(struct lws *wsi)
 		 * For the duration of this http transaction, bind us to the
 		 * associated protocol
 		 */
-		if (hit->origin_protocol == LWSMPRO_CALLBACK) {
-
-			for (n = 0; n < (unsigned int)wsi->vhost->count_protocols; n++)
-				if (!strcmp(wsi->vhost->protocols[n].name,
-					   hit->origin)) {
 
-					if (wsi->protocol != &wsi->vhost->protocols[n])
-						if (!wsi->user_space_externally_allocated)
-							lws_free_set_NULL(wsi->user_space);
-					wsi->protocol = &wsi->vhost->protocols[n];
-					if (lws_ensure_user_space(wsi)) {
-						lwsl_err("Unable to allocate user space\n");
-
-						return 1;
+		if (hit->origin_protocol == LWSMPRO_CALLBACK ||
+		    (hit->protocol && lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))) {
+			if (! hit->protocol) {
+				for (n = 0; n < (unsigned int)wsi->vhost->count_protocols; n++)
+					if (!strcmp(wsi->vhost->protocols[n].name,
+						   hit->origin)) {
+
+						if (wsi->protocol != &wsi->vhost->protocols[n])
+							if (!wsi->user_space_externally_allocated)
+								lws_free_set_NULL(wsi->user_space);
+						wsi->protocol = &wsi->vhost->protocols[n];
+						if (lws_ensure_user_space(wsi)) {
+							lwsl_err("Unable to allocate user space\n");
+
+							return 1;
+						}
+						break;
 					}
-					break;
-				}
 
-			if (n == wsi->vhost->count_protocols) {
-				n = -1;
-				lwsl_err("Unable to find plugin '%s'\n",
-					 hit->origin);
+				if (n == wsi->vhost->count_protocols) {
+					n = -1;
+					lwsl_err("Unable to find plugin '%s'\n",
+						 hit->origin);
+				}
 			}
-
 			n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
-						    wsi->user_space, uri_ptr, uri_len);
+						    wsi->user_space,
+						    uri_ptr + hit->mountpoint_len,
+						    uri_len - hit->mountpoint_len);
 
 			goto after;
 		}
@@ -765,17 +867,35 @@ lws_http_action(struct lws *wsi)
 		wsi->cache_revalidate = hit->cache_revalidate;
 		wsi->cache_intermediaries = hit->cache_intermediaries;
 
+
 		n = lws_http_serve(wsi, s, hit->origin, hit);
 		if (n) {
 			/*
 			 * 	lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
 			 */
-			n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
+			if (hit->protocol) {
+				const struct lws_protocols *pp = lws_vhost_name_to_protocol(
+						wsi->vhost, hit->protocol);
+
+				wsi->protocol = pp;
+				if (lws_ensure_user_space(wsi)) {
+					lwsl_err("Unable to allocate user space\n");
+					return 1;
+				}
+
+				n = pp->callback(wsi, LWS_CALLBACK_HTTP,
+						 wsi->user_space,
+						 uri_ptr + hit->mountpoint_len,
+						 uri_len - hit->mountpoint_len);
+			} else
+				n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
 					    wsi->user_space, uri_ptr, uri_len);
 		}
 	} else {
 		/* deferred cleanup and reset to protocols[0] */
 
+		lwsl_notice("no hit\n");
+
 		if (wsi->protocol != &wsi->vhost->protocols[0])
 			if (!wsi->user_space_externally_allocated)
 				lws_free_set_NULL(wsi->user_space);
@@ -1283,6 +1403,7 @@ lws_http_transaction_completed(struct lws *wsi)
 	wsi->state = LWSS_HTTP;
 	wsi->mode = LWSCM_HTTP_SERVING;
 	wsi->u.http.content_length = 0;
+	wsi->u.http.content_remain = 0;
 	wsi->hdr_parsing_completed = 0;
 #ifdef LWS_WITH_ACCESS_LOG
 	wsi->access_log.sent = 0;
@@ -1813,8 +1934,16 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
 					 (unsigned char *)content_type,
 					 strlen(content_type), &p, end))
 		return -1;
-	if (lws_add_http_header_content_length(wsi, wsi->u.http.filelen, &p, end))
-		return -1;
+
+	if (!wsi->sending_chunked) {
+		if (lws_add_http_header_content_length(wsi, wsi->u.http.filelen, &p, end))
+			return -1;
+	} else {
+		if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING,
+						 (unsigned char *)"chunked",
+						 7, &p, end))
+			return -1;
+	}
 
 	if (wsi->cache_secs && wsi->cache_reuse) {
 		if (wsi->cache_revalidate) {
@@ -2277,8 +2406,6 @@ lws_urldecode_s_destroy(struct lws_urldecode_stateful *s)
 {
 	int ret = 0;
 
-	lwsl_notice("%s\n", __func__);
-
 	if (s->state != US_IDLE)
 		ret = -1;
 
diff --git a/plugins/generic-sessions/assets/admin-login.html b/plugins/generic-sessions/assets/admin-login.html
new file mode 100644
index 00000000..113df9cd
--- /dev/null
+++ b/plugins/generic-sessions/assets/admin-login.html
@@ -0,0 +1,5 @@
+<html>
+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.
+</html>
diff --git a/plugins/generic-sessions/assets/failed-login.html b/plugins/generic-sessions/assets/failed-login.html
new file mode 100644
index 00000000..9ab065b5
--- /dev/null
+++ b/plugins/generic-sessions/assets/failed-login.html
@@ -0,0 +1,3 @@
+<html>
+This is an example destination that will appear after a failed login
+</html>
diff --git a/plugins/generic-sessions/assets/index.html b/plugins/generic-sessions/assets/index.html
new file mode 100644
index 00000000..ea970eec
--- /dev/null
+++ b/plugins/generic-sessions/assets/index.html
@@ -0,0 +1,35 @@
+<html>
+ <head>
+  <script src="lwsgs.js"></script>
+  <style>
+     .body { font-size: 12 }
+     .gstitle { font-size: 18 }
+  </style>
+  </head>
+  <body style="background-image:url(seats.jpg)">
+    <table style="width:100%;transition: max-height 2s;">
+     <tr>
+      <td style="vertical-align:top;text-align:left;width=200px">
+       <img src="lwsgs-logo.png">
+      </td>
+      <td style="vertical-align:top;float:right">
+	<div id=lwsgs style="text-align:right;background-color: rgba(255, 255, 255, 0.8);"></div>
+      </td>
+     </tr>
+     <tr><td colspan=2>
+     	<div id="nolog" style="display:none">
+     	Register / Login to see the messages
+     	</div>
+     	<div id="logged" style="display:none">
+     	Logged in
+     	</div>
+     </td></tr>
+    </table>
+   </form>
+   <script>lwsgs_initial();
+   document.getElementById("nolog").style.display = !!lwsgs_user ? "none" : "inline";
+   document.getElementById("logged").style.display = !lwsgs_user ? "none" : "inline";
+   </script>
+ </body>
+</html>
+
diff --git a/plugins/generic-sessions/assets/lwsgs-logo.png b/plugins/generic-sessions/assets/lwsgs-logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..723a124431189c21c340de517bd9b82cb35374d8
GIT binary patch
literal 9729
zcmeAS@N?(olHy`uVBq!ia0y~yU^v0Rz~Ilp#=yX^?rqmU1_lO}VkgfK4h{~E8jh3>
z1_lPs0*}aI1_qTmAj}xq{LPYqfkCpwHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#
z_B$IX1_lKNPZ!6KiaBp%D`P^Q-uusYnCCFxre=k1C9STdFGB?i6a{>RRnNv4ZO==c
zsjHWnxLxP<zUzDLU7x*kLYm%8?{^vR7CF6J(vb6rZPWYHIs3o&FSk6GD8?pnrRw?b
zpL6)<d|vbX%+I;^fBlhT6cqF^ILNZrp!$-q!NHd0l4?wb2U%<l1Uop@UNm+(_!v0y
z`>-T6aaJWL2?+aKU>0tik<cVJgX0K`@RtKF3TiVJutT-fUlKM@>)<e&$s?{8<B*uB
zn3a{KAj0+V@#E%sw$+CY9%Ov>tbS#**}}OWr&mV5ySKM{vbw*Lsw%5_{ymq{Qqv_t
znrF_ONyyITHa9otkuYE|G&Fp1YpZsPQ{wKks`~o;udl6j4hj+~DlQI;i{sPQ*8cJ1
z#{&QPb`o|q7D>s;4_~~vkyl)CX~oKw2dm%jZNI$S|M2C@!rs&MTq7cGOr95Z+OeMT
z&%fXAx77SB;^O61RaaLR;%a4Sux4Rm>~vA$;^SLZ`T5z!PGR*G+qPYM@i{<i>Xwv~
zLYp>hc+k84twqU;2^Wvo&-(DNUH;R%>jw`uW@Tl~`?4jf$KIBGXYFsZZ*Oik>qc*T
z@a*jDJEapnSi-}@ckJHntRl2<&mNiW`S*`)%e@^C9nEcRZEf@W&1Sc`r{CP%ys_-<
zt+dyitxh~L78h0|+vf)S*JW6+Xc1HS`+Ked0T+a41-|~UTuoqUQ0L#@-yc7pUw`d~
z<D9v31!ZM>Z`_EuaqE_nu5Rz@@>f?hE2^s(hp&%wyX<L}duz#53l$;GKY#uxOh5hc
z!9nIL*RCn4sIZikmAOfN&vXq55&8E1{`tA(udnekGBWxXxUD@hIW2K*YtYIiU0qzW
z3=)}c-ny05VNh6DSn}kAV33B$k^l`4waFKc^-8ad-(Q!KnCN)8jd$^$JvNh0Kh2%z
zU0P~d`r<;P`MwC9Wlv8}4=yb=U7zRX#wKfBw&rZI-P-`Isb4Pp+h5#M`T51`_4}7y
zx^zk1c4^o{|I?07iY)!+*>t{nlXK<j)xztnOpG}>IRcWBopQES4}N`pePd^_`kXm)
z1Ox>e7c5YS*;^&5s;YY8+_|>)cK6w$-*lt5Em*Urr~K{y|9|!4s^6OS?uy-A=6Zcy
z>}`{K^BI{M89sje*wNo#e<?Uqm`8oW8l49h6dzn#S~iD|Av|0`kFVmHq=VAM$li{C
zprEE*yR0-sxO$D$)zzm=pZ@s5LgyR1%k_`-$#(zwQxg&v=Cm@zX=R91?kQ>WyeD(N
zzr8Jfd6{o^Y5n*2_mA%^es1wP{Qtkd7ngdAH{aG4;aak6*`tHa>>D<0aLCBW*etfW
z`un?we|~<}(ARI@y4Cd8*Voq<85S28Pn<ow`@jK*A3uIb-0`~__Vr>>Nr_89fI!u^
zH#ZmA-Qs2YJZq25qW?eTmEz--CU$US%s+f{X2vt0MajoIUcD;uTfT5%<G#P&qF-HG
zJ3FlV>Z;Jy8k(A&Y3JwpUb}Y9r09u9S9kZ~h6V<qP8XAe0}Q*WzG`_cy=1oWL0cP}
zQ1{V2mTO{mZVIh^`t<2VZv8zDOpOlCDLq|Xi++E9|M}JX+uQrKw{PC8yfenny-!9l
zK0ZD!T3TBA)|Sl4*9?n`iZYIL2u2<6>Fc{D@p*cD-NRGPPEH<r(=V@y+`Qx4yLazg
zTuL4sV2q0wR`<J7wg0^R|2<*a@!Rw6YM7dC4LyHxhQXZXl2<G}vfMT`9B*#1PMON+
z_J_-PA;YTGjgy2Dp8GjyvAQTd*!jGqNJxpvG&0D)-hzAcrcD<%CcFRm@#DauLrk8Y
zo)b<#H83`AZf|F=`ud7hUw^$>cX;@^n8pyTr?JvTDIVRwPo6sE<l@4@#l^K{n!Ih5
zh;uuitCv?-80-F3tGNFEd2YY4;$zZ@r$up*zP`L^XJ#}uGP8dYd3xrIkBghzq754Y
zUeECK^pr5mkq8P3O32P$9XM~=w6@gK(;n`Azwhz7(pOhbF8Hmhq2b`-!t(CU&c$18
zY;FIpG)R%~Q($6z@RnC6;=sPI+w(V1zagQ(l$F(>9p11?%dKX2IrG%12h`^?+}+Kb
zw9(Dj*w~nZg=uZ<vgON_ZER!&1qFAMyc7xw3R0Nrm6)5`d$5`P@zn6R#?70HXD^>O
zefo04<>%&FZ(qT`G^kTEcv*%(dxXw2!FV?}wtYXJN!R@Ocs%NN<c5UCbB0TTH0%C+
zbYHjDY2kq>n!zR=i(k%o`SNAN&LUMY{kS!y_k5oxt*H3=@Av!HDtrtdzJIURD%m<s
z^JQ9ELo@S-m&=bmm1B4;WB-TY&vSc+M8(Hy$NQO=E<I5HpS$E8PejBD-=jQwdU_iI
zb}#FD@+8H=(z0-0=j!nFi#BW!*tc)ri%Uzntx8@bOvwxn3;T5L?c2AC7Z+P+9^ROI
zyx`#>)^~Rf9%S5I{@$&k!lF;cvgzVt_hS9G{PuqqOm<*c5Wl}JVn>1E6fae~9}k$H
zJbPA@I{nI*<MH)>MOUs|d1vS1#mZ&x@AW!1vpxLq@NmV)qvDE_Pwp_>D%io5v{B-`
z{ePPdj=k02^S;$_b8~OZy=``HYexr%PSh3-p-z_T>*LK=_1zHLa;HmG;6>;>MuT%f
zK}=7cGk^Wsu+>!fVoa>$#LVX9>IS(|3X>V5w;3#U@Z~LdEA`>q?E{Nk9sd7o=;fWg
zW2fb>udmtt{r&IksSI{LlbMlmU}N&}fS8z`iOTLtpPrn2ad)@5iV&xY5a*eavx{3Z
zycDioySC>uue4c4hmBT`thJb*pWls*$?Wfc9ctwkl$7LT=;-Wp^zq^O_U<k>!-;d}
z+&n!y!`?lA`?fdvc;CTi{pnY3-00{ORxf(`N@mr|8Qo&KpajmKU}h$E@#4if@{g~r
zjn>fCzWgh2qKAq_^*5bgUtTW$D!29FfktK<rh=lPL;wE%-dWk+-Y$J7y!!Buw0qj&
zH>Ur;q`F{_%!Jc3^&UPv824eJGh;5Fa&fVnivIpHx8B@hU9#L*X=efBkMH{>8C~6&
z`1k}kSPF`ZoA>Xxw<>wDKv7F$s@Ie$Qxr^1MV~%>nvs!l;L6J2-eZ<LM{nov@4a;^
zYHjM@-{0FOPZrjT-*;yBzenBrpUycuIax3<HavQiw3bCkPVU^^6ow0{!}a5K?y|fy
z!SJeV?a`x0qvprv<m7aBFf*)+-F?iuzq|YK+25H>g`7_=sV4j`OSo^RU_AMyn3ji1
zkF<y=<79Q_xVRpTS&Op6A1s|75xsLx;iO$w53a{EE}Rf6ZN~FM*~nZ&gF{YEE=tr_
z$*Hu|^wOnE0g;iM=H}){jvP5~`0(M3?RP>dL+d$tUCYYMzVCNXaPafv^S9ey{$6hV
zKE02NSK2*$@Zf-TxOs+&tg*GV^!EJw&(_`DUw?mr;a1J}XB}hTFeiMOAfJ55g2jo&
z#KhoY#&bWlsLrDf?R*Z$`+VY8u1o8xO;S>x_VKY~_(eCBRr>Rt7<2CNh=>>{S(bEk
z<|qjoR2U>=cc;&<6+3zI<c`wU)6VH{^-**7^W!tiyTdWjqvgemj2%06NIbnZyY8o!
zmez#}7Y@8s%*@OLrI)fYGrjnIJ*BU&eS9S>n3a`P@qFXPjaA1@rf|O!Ql9Fi`aV)n
zu#I0nZ;Byr<FCI=K1Zse5@nbsdflA<??d8)cd_3tRaY=<+<4&2ONV6T3DekQEEr_0
z*=qh-K6rEHRBY_l?>ASACuE+qIM&8{X4lmV2aat2RCM4JmxKXB{p<VkFJHd&@b^Ey
zHT$~BnSHM;N?(ag@lx&Jczmq4dFj&B+4*<RpYJbU7os(B?%du74-(ehIe(r%Ffj1M
znKM@u1X`UIK74V7otv9`$IhKwGtU+6+~exC!9}TY^}72jMKf0EZ@aSMqeY?&)5=vz
zX*V|+9rLZJnK5HafnxQ<&Kc=@yv2{%etW}cmdjN2<$|vQ!-MzyXXc(3`98lc>6-4$
zp3bb|XAJ-UsIw#{N|<B_6crawoH((ut&MGOu&<|QW6;VLAGOO;T$h5rytygN)Y#xY
zL*0Mg6OJX8GiJ~J?6dmZxpNVFtG1r|HEr6oTr-1?qe(Mn&n`a393CG2=ehm=i;?$F
zo$^|4xz{w~SE81lo>|oWV{L^TE^5q0#ggiQf*$wxHSAjKu99?pnLqox`|Npl66&3u
zw*0bSFqnJz?%c?YSy?kWLIVyQ)6`9!<GHeB`*!n1ix*FvKD~Wy^me8OKR>0ZUWI>u
zm8z(z9XfM{M}O}Zp*3sPMAg3L<KyGt;c-bzQ!CdsG!)F=_jB1n{i)sE-0Gjh!@`oz
z%rJbr@6*MjM_V^%g@%ME=;^JC6`#0r@k)=WQ>T87IF`%Xll(d-gJE5K`Y*-<A|Kw}
zm7n_j3B&$BOmnQ+Ev$^3GILn6vS)H!m1#NTt|WF~hhL42^x<1lLY*uJ4<4Lhk}0%k
z@nTb-wZ4I|vAx;X*CpQFReED<cKGc53Htm07`^}V>FMc+&1t;{-|jAbeeAFP<dX&8
z-rO`hyL@S~*U}&rb@lDPXK4NS{rmH|?{98?zHuy1v&UJ%NV4GlJ>~Peyez{Xen?ac
zySw9{NZHa!g}fUhw#Tz1{Jp#L@R5zDr%O)UvCD|H_E*Wg&lfIU6kND);g8?<|M#6Z
zaUxB0|EpJ7f4<$$kJz3k+b3tc%J|M90iU^6qL0*K3eL^3{PAY<`GC;SqrKY`53{X(
z+s-F@%KHD0$Ni>HzU<m%HP3kCT7#4`w{Ar(?px_}dFggZNl6>Q{*Ho=k6ah`-<FbS
z@8@QDqrF~8Q$^_9LUsm=+F6m?tjbdAgM(%Wy??SKde5Yj5`}N>o~}_4746xutAx?5
zpKZ&HdvD*oG03{2!O`l(!NN4hvY1U&RMcv@?o_YBS64JSTAgOhoT;d$=62X5i=(Et
z*0B6tOwHG;;de}T#`LLrPfK`tX=y=GkyByeM!%y!riRBkIyo^(NlP;_q@SDPxIS*L
zfVen&baeESr%w~#-`lI8^yK+-Y1fstPp5`|c)5IjQSv;i(k}C~yga>cZ*Q|Vti5Hj
zOv$$7MSz91_2MN<T6UYIpOaY=zhCa%yLTr}oNx#X6g+k6REe9HjhTe%laJSQmF(@6
zHqLN;Qujk~|DU_%omQnvo3^SJ6)SJrt{%0aLBl$_y539m;#_MN?J$9xHw8Ia*2Fh9
zWV{Gi)Xd(QVzf8ds^Wt}uav2m@};orhDA?2tSUYvtd@7o&DCvfZ<jU^``2N0?!<`)
zxAY@79a&IzzxKQAbvN5t;tamCOghb%v-8V+IJLX{{W<ObFBbRnNEP4RRT?AxH6xC}
zr1VwD+VhKdX516i4l}WScX`8xGZsqI91d7Cb~RtQZoI#p%Q)R=?!oKRTj%IRF#P%Z
z{!M+Zh7L>JAHj%?O`6YNS=7&)*~u?ow`6jLV@irjT>anD9vRC^3!*jj^o|{F=jUCu
znl~&g%%b1{gPQ-mJ8O#GJ$>5B%+B|r>7$U4kU{Y?pS^F_{J*fhr`6y7ugK-){@0_A
zA3L@z_RNO&dp`4}otd$4bBuz3g1!Cy7mv4z9BOH4VOjh|Wg^4=|L4B6{Hj`3^ZnIP
zj^pS0I^8BtJo8;p>eL~xEs<Grb}ZM{v2M#{{`6@^=$UhT0hQ6GPtA~5F`oR=DlhNM
zlsha+6FJVEJ6BLx=vZ58TU1o^<<>u28=DVrHlN>ia<#Ttw_(~Di6h639XfZ8&uAtO
zQzJuISlEZJUtN8Cc%Ge~-*1|IEki|LfP<ytVXL@+oZPvYy}CL&51u}4y>KC5&(CMG
zJ$!sz{{Q>C)68k1z`S|$Kn>wGUg@@j&Fsns1{1C?-@Df~+^*zBz`ehmEKEI8rd-Wz
zyi5mbEQC5);^N{sxVaBU=kIOhl{N#l=Jpuw-Lt2pZ)JYoD|wcyH}+P4e|E_@GAc?*
zL4l#LurOk4*3^UY+sj%5e@qDRnlj&iONL<JbUl}A*Idrqx_^0JFFbXckfzAl?~2nm
z?~1SU6cIXf#B||=6IZ9c`1`$cTW<2As00P!tw)j;9c=D2%T>zSw8C9BH8pih{r@^C
zqm+(oTVJnQoPU4cma?}|i*5LX|5+LEu?uoBR#zVr&B~tXs%<{Kb()2RL44cRugZdJ
zG@le5vn+ehw(mFJj?(Vf&tF*FdJ_B&?*H5Sb#Z`!;F>K{zQ)I%{Z&@Vy5$IKWK`6l
zt5-!+Q&T;>y&tdf@_qR7W#_)y-*#6E9o1~=B(6(eT`O&n%2nODJ%`cAs3G;V1f%VL
z8{zg@vr4CWxyiWqZz@$&Rb8{Uo4fl@?R(p_bEd}0)3iHVzD}RPAtJt6!ENP~uf|m-
zn|n<6dKMSwr7q-D+ro0J{CZmpL-2AVz7KD=_e}otSpJQwoc+A_vFtO>O`38fj89C&
zKrcCwkw>2I%xrcOUz2N#*@Hj0Ds9`bYR{aR6IZX2NIW}Z;lY(1FIGl2Bp;g3{Z{z=
zg}v4vUaj_tyuYcH)!^Uz|3)9PpZTZ>G5Xlt+B35=REvAkOiAwc`mdp4zt-`}$sKsT
z-dOej@Ar~|X(<fZ*EXacOiZk?=P7BQw?#a~NOE2L{=TLrrV}Yf78Vu<u3s15w{M?Y
zZ+4Z82B?Dk@_9b*TW19^F`qlLEI(hobaRbP+RPxW#>mYxN?-kc-?%oq@lDP%36_S5
z%8|F`&$BJH7Cd`)=8kWtw0oj+?w`}iaCJSibA@uv(?S8y)Kpa=A)yH~W~|tFOCX`K
zG5J^zsC2w@_wMalyIjV<f>rfDJ|woZwm!TbU;npWec85nmpNNayC2m4E&X<Ap6zL;
zd!k&&R682x*FQU6z<6f6qR1;XKG8F0BDTEWQP|^A_iyG){jXo6uAjE&d!(VE;gFJ|
zl6QC4(#?K>fr8i8$M-Mwp1$pO&8@CIdu(LvY9ts6zP*Wz*-_9KJ?-~@*0<6|S&581
zl7}`;))4Ut|M9n6%!<ii<EnlCCZ2O(S+Z=?idc8|W#>CwejVrFO7in4F5Y&{rTxbz
z3yvpu%kMw!P}b4m;TG3(*`9YdAv?SK(W9i8-DSMiWp5gSR_1)3)pwjxTwMId&6^8X
zt>Q}Bc;mqoyLwfdc~=(e?>n)>qt^DZ%Bz({Z{Ez<r!d`kb%-nL>AXcDMw@e|>-}Pu
zVpK4gur~Gk*VJPSx{0^n`YMEmhThnkeO>-C=aGrZ?iH`)=FFXYac#7@&kTcy{>cU#
zwr)N8^78V+7Z(&=+}sXbzy96R|K-NV9|bxb7<wcR@B8%hX+zbLXAcgZ*&P?bu_DH3
z=~ADa>sK@H`!lI<@-vZWd3mw4`0(#1I2N>hQ=1@do>!1rly+{;%JQv?HX5z6;cIDW
zQBYBN;_3gm^WjI;^=9VmA)j6!mp4vN2oc#F*4l1=N!~0c;Z#|rrSX5J1L^Y(|GO1)
zSG72~$wb9DT$<E+aYlguwGZh6^L-3>`ptLmUaV|<P%rY3OwFntYxrbm%rMQBQl4a6
z9T8EJsL1WLWh-mi`Lvf!vy>;PJIF9pWN*`t-PLk(vikO2>nBYTnqyxtw{+>!4`05x
ze1CWMVqk4;uh^4k&mKKG+Pz}MiiXLPg_)R{1!ZK`TwUVhvZLmw(WT3mFW$JpAucZd
z<=x%gM?IHcRh)cs!kjrh*5&UUbi|Ym3<S>GeD>+~xmEt|&cUhL;Q>)mT>1I=Ev>CD
zpB^zaHTCfGJGQs_yMkEv#f{1CHs9|QAM;hbBKJ|-Yw4s{uV1g+v17)nRjXDkT-YeG
zszRr=X~nWO4b|48ai&L)cDv;7Ie6$Xqf&9PlD_^Te>=rpg@-rnSf{pP&6*|e_x<ks
z^XJbkU9r^*7dGBjK62~UEF)v%=sWJAp`vGJnRdG<3FhaerKOn^K62^Z>lTvx=<(yN
zYV+S+TFU+Q=H~YB|JT+=e>r1(KBJax;lhO_kB{-j)rJ<mWMpQ0G3WcOt=T7U-i%zl
zzoCJ_s_03_HM9Kvf6W*doSkhR?CHtbD{nvV%$YM4Z|~l{`|`|8<EY#DH#RiBdHdG%
z*p_YEmd!LyH~YSVw=IyvMQ?g=V4&dLU8UW6vAbN3_scJrwJy8x>gwv3zu)g)KELi)
z=eM`F-P6y_S$O7*&#HCn)RqRV+<ka+dS}{swW9L+DPQlN?|-rR{Eb_}wYggtY}z#G
z+M3AA>sXvzzWn?BzWDFY-@k+N^41;9m6npyFfy8you8QK`0w98o21H@OQ)OM0yQ+W
z#k-F_dHmQ}sIz7Fw(RSA>++J5l}q2<nW?>b(<UW(d3hsq^XD8JH*A=2y}p=bQ_at!
zd&OVAe0j2W$Fpb8rc9Z#<f5Oe!sBDTiyu5lU~+I;IH9JdrlQ(r*Up`RuCA=>-*yVC
zR~&ir>Xp~Jb?ff@{P6HFZ{54I3w>D@1!%0;wryHbaj~YM;lz8j-(#f=lUPdM-kO?|
zle2@9yVYsa#*GUnOc0o5U9LCRqOeKMuExWtwtL>B$(?bvQ*}29b>0vZaoLh185kMa
z{VXyv((``Z@7&$O9-*P4KY#!JTz5xU-B04mw{HD?4{q)Ke9l^Cd&Q3rimom$1*y~Z
z<DcD{GHqIs{;3NKohx@+q^71`OrKwS?Dm?F+QzHZ@An?h{i`tfq=u?$YuK8Ig@*dI
zEJcrx@%HVoDu3q_zAi>l>08{I$jxoa@BHRk1v)!3uV35c5ORD^<>wvM>sGB=6u8)}
zF!lBI_0PBV_V=qZs7&;zkXg2BRoAxM+sh_rZ)M9>nlNdS(5=1I=Dl*Zv(~I#d-Bks
zCKn|^&Q>S6)8ZT~DgqoH8X}YC&XsL#X}NHym0MF=+q?XEk>$mu-Y%2XH`{vt`P;dx
zT)nGX`PajCv9rOh3claZ8kjW-2rgZ|{PVsvr-c)y=|(S`o@{1jHfix<WyS?FW=QmY
z`u+WVv9|JboybG6_T}$n%+I~MyL<NB*}tyu+p*)ug5MY26^zr)JgB?BI(&WB6#ck8
zGo<rhUt7D!sFbPl@7L?5x6)Em3!h$I=KFZ+N(;Z7oHdT$FNkfqb+6*vo5-4fKc7eJ
zD$(?tYt_1ImzBrTpc5%Z8X{ctf_&;VPBJwzaJ4f1{Q2|7jzVS7KyJ*=BG=yxPKw;&
zo*oH_AFRtaZJ46Jk73c`Xq)&dpN$cYj*cF_zE3yJ(H7wXjbeTL_|eMPUe3CV=jqd@
z3=w+wmwov1<wye~GXul^zu%<GV`CZ3RDQ;IzcyzN-S^<c36HhQ9#|GXD|p!*^7{5{
zCmpfJm;LRp?zp$JI6bd@^|H*yknan%HFp?ZOwtw;RMgk!xBvS^_}lyY{ng*!6@IIC
zUJ#&h;l_=QQ>VP%+}k_b`_Zy}S-s6mRk_tOm0O$?ZES2V?60q%doLlhFFtue@Nz#;
zNp@zY@y68CVhjh)&9$C5d2;jL-`@|PKHVK2Un|WN+quBj)|QcB>C&Zlwl*{{aI`vU
zh;aRR9smE(hlhv1KKl_AfAq)C=kp)mU)9kT_Tb;&-x^w4ObmIhNx?gI?ONpCFSn!Y
zt<<`>y{oqNZQZ){oP&qIzkf<<YUY}UFK=ztzI5qQ!Ji+6bL{Kq{jS);9_6FJ)yl-q
zFL$I<Sbf6$`S}~dBNPM*jx6|9_4L`ZqMKGNPKn){Tco+Txw%=`*^^IA(X`tCNY<+4
z!inow#3CXiA0C&lKXPHAvtjx<nJZVXK74g`HE5`=sK_Y)`;sqTN*HqTC(fEB)q7{_
z0p;gOd!z2m>h9(~)+^oq_V)J2cXk$cbafs2_V#w^td{xp|0;j{{0R!;)nRL$YHMx7
z*2Uahb)@oDe5vTiEN2G?&|p{Fn>RUrT?QhnY7VSAqpfvjo~^X~|3Ai0iYyl`TC}0?
zv0IO<^|sdX1cfN2eoYZBEp6?^D^_T%JsmD9BXi>V_367xUOL^ocP}M9{kY~tE!!oT
z(hQ(dEq~unwbZn<pycGm7oVO`@7=P+<kgLh%H{hvr=Nc|_4Tdg{<klNh-+wREjn<(
zVcnf$$J#(c%5$yGw{nYDuubusYjyGA;r7yVvD5iBrJt8u*Dq^b_9Dl=_?geTIA34h
z^4O)#7FJfTa;)qAR4_Tj?k>Bk@%zJJ{>t;IS5^du1OzPDy#CrES1XU?WaUqvK24Z8
z^JMK)7AD3sXU{%-@StJC1_Ph@cCy9K&mDboa`MIX@%A@v-!3lFczJ>O-JPAyYooV6
zdcA(XTU=aRx63wr=BDQ6!aqL>^OoP-ntlD#w!Gj%(}e*X?(Xh;-GkHTb$4?I1qB%-
z9%5lQQ)yQIE(SE-diB-J)PD~D|NZ@VJAePe{QLVD8vgvLIdbe+(#uOrbuV4MV!3f&
zOwy~!htZo&Tl93|_sMj2cFL&V+g+~z>&wgL;^*fib9oqaA1kP;s%|NK>{e7<{CG#B
zhsq+o*j*Q9nPzL)+t1I+&R)50U0+sK){A#{cW)_q8T9JP%E^B37FwM-bLPaQOOuxQ
z&-Yuoa^;l^7d}MruMGKhV&+Z1h`m*&<@@97eyWz&et2;3&h<UIpjoiW%F4oI9!aB?
zCq+B2?Fw2sW#5lS+?%#+dGbm>ZcoJGd3t=Cl8^JPySuOUcgeZTb8{?XY)k9iqAfeP
ze*XLkng+__$<EF`cPEEui<f8k|JP5Rv~1X50P3opJ9lnJ-CrvsBcls9Zg8lptNY9{
z;gq#1Ik3!kHfWq<ZoKBwpw3^vs@~k*&L6%mrt*z7Uu1MNXo6z>zF%3pbyH?p6e``T
zc+AUCBN<n^UTf+0tsULnhaVhlHmv%R0UF&n-Y<XrSg-Wfw2k7OE)g3N7#A&GEGR14
zdg)S7&CjRPXIK;}>F2N4Tk+if+Vs6asUZR!EN?%}{`KQW!u@@<KmL3^51O92a_!oq
zUh{hfQtFw4jVoL<zh;DlhljVcwH-QpmN$G|%)w>8vnR}&#kDhrFFifoXNCbIGdo{P
z(8`to4Hqx3uDGzckdQ0S#Fv^1bRXSO|KILOk!9N1S*+^n>WkB@w{PFx-rLKYm6cWT
zs9&pR&%S+fPoF-Wqj62j!piE=^!PeQ2M2~zr%!);+;9Kt?z4w8)8`#r7rR?PP>^wF
zOyAqv+Ye80F@Lpa-oE?ZQ{%2kMCZLe>@Hv1a(jDz^4(pf7WMyZii(OVqT{xU>0WZw
z(b0ME{5iY2y1HKEW*4Q0PtHi2=P77wbMwpF9l5)^yzs|69VZ3`)*{eafJa9-L1Qso
ztxOv?ZmjtEbo#~R{_-3wP0RCQw}oiAy1B8L<=^W$JKKEwjhb8zEp2Vfo3XY#Hm0AS
zcjy0d|M_{JE&BTUI{qCFU$XD&EWMWY_Tp*!&aary_$&TOHk`eV<+{s}x9&G$ZEx3G
zJKCP!xA6N#nJ6EHfB*iyxVl>W&D*z(8`eD4DqbI<<M#jGU&Ev$94##^3pQ>PT)A@P
ziIXQAL4{k7Wb^g7YTmil<!w86{tWh1v9z@O@oM$@f(Hi}@9Zu=zvA2q-RNxvcY^Ph
z$xBP0w(SmG9VVG;bD)4dGx*|8%ZP}Gf`9$Z?EIhp7;DY3tDWWjTuN9tIbeS-qiLa^
zG_$UfK%)agr%Thr!|jJ}-<Eb-DB$YqYEk}9=G3WE0wN+U8<USeY88)jcz$j!<A&+)
zzP-H-nq=L+-5gZx^4tAjkdu>(5&O2BvuLM`tE;PrhsS|`e}4ytgrr<Jtf#Ac^v1^I
z!he4%dyQuLv~A74{%G&_d&~!R9Di|f@y;TBeSJ_SVfehN{?kcysbn!x(ZboxD;1`C
znQjYVYuH`>{?Utziy01lE_nX*Y37?eZU#?J&pT{(zU9ZRwtG%iV@wcR8@V~{qn%o6
zYHCbK!_=vw$NJ^-3-+IV_~hi|C{80oLqUdW|L7w5s*6%*_bpn~WcTZZG8YGj!omO#
zS*wx-g34|e?Eih_kJ^~T>O0%4_s^d{C(fMdk&%&kaiEboBs|>R<;?V;xH!Mn;p>;>
z-Q8uHeYZ-eT`TX*`SbnLbfew)<?V95&0G_+b5i#Er%zokUc4wGFYoW%#-nI%Za#0T
zpY5Tr)}9`oIFX!!0)xGOzuh*e|5qbrTV)a%6*b94X(2nmTtV))cXz!RxV7c&>uhR2
z9Ay7;D|>z6Uk(<gIF+@h$}eoskDp~#s&#h0{rqD+l80GkZr!}ORby7T+T@Q;&#S+@
zaQyu2>|*nK70q|<-re~+zUE`A+wE&n8%4NSD=RA}PMs=x^vID5(fNB_-|zda_x0V~
z+0y!Uc5(mvuQF}va+u<!nwpk&Nqv5eQ)6SJiU`-qd-vx3`TJMXz+l3iyLV5XI@M)k
zW0P@ij^&i8Q;!zMXioL2`tX2pZN$c=U*F#TKEmmAT~Vl0!@^?5G`-kcIulh?R6ZO!
zvsE@PFHh>V@s+|~Uot;^_;BH-or%emcXxIkzB=E&e&4xWP75dO`}Zq5?msg--<8Pw
z7cWlile1lAxcu3nyYKJrcCY>Q<)USKE4O%7?)509ot2-L-P6@|a(1o^Je%9vu%h(P
zte}-HRaI7?Hs6ycDJiL`h1YmGU6}Io^IcqA5`KJm$ic;RX_szPT$~(e_Hu3Xb~{sR
zF4NZ5R#qlvX2ZHa6=!A`GM_tl&T6gU(xpppY|R!2P3JT<F<rTKt?1?@c3!EL9XocU
zm0#1<*FS!3ZFJ$gJC-&zKLpIo%wF8vYn_yowB?wMs=E5)6BCtpRDM>|($Y%E%<P<J
zTb*=jisqi2R}95p)Kpa;URfConl6fsm3{N}?Z@r=|MFg5=6iXU_H?g)&@ABuMdvN&
zBK4*xpPy%IQS-w<&ZdH)xVZSsi;K*{>V8io6|NM1eHEILn(C+{_W6i!Y0QoS#`5>~
zTGy`C^>45I@PM)I=Tq^RJr#oA-`{5!Jb3%Iw6a^zffpAS_wIVO|0>HOCs$Y2OP4Pf
zetzaFA|lezk&v6q3+e~AwH>;9H}-u?aZyphqa&Tice%%TFN`{8S^KMG$IhL$+s^9w
zR(#4ZZk&;DC|<ID-XCMN86Q{(E>t40w&{<&uyaq?Hs!gq85kHCJYD@<);T3K0RUg*
By;T4J

literal 0
HcmV?d00001

diff --git a/plugins/generic-sessions/assets/lwsgs.js b/plugins/generic-sessions/assets/lwsgs.js
new file mode 100644
index 00000000..5362c9a9
--- /dev/null
+++ b/plugins/generic-sessions/assets/lwsgs.js
@@ -0,0 +1,476 @@
+<!-- lwsgs rewrites the below $vars $v $v into the correct values on the fly -->
+
+var lwsgs_user = "$lwsgs_user";
+var lwsgs_auth = "$lwsgs_auth";
+var lwsgs_email = "$lwsgs_email";
+
+var lwsgs_html = '\
+	<div id="dlogin" style="display:none"> \
+        <form action="lwsgs-login" method="post"> \
+         <input type="hidden" name="admin" value="needadmin/admin-login.html"> \
+         <input type="hidden" name="good" value="index.html"> \
+         <input type="hidden" name="bad" value="failed-login.html"> \
+         <input type="hidden" name="forgot-good" value="sent-forgot-ok.html"> \
+         <input type="hidden" name="forgot-bad" value="sent-forgot-fail.html">\
+         <input type="hidden" name="forgot-post-good" value="post-forgot-ok.html">\
+         <input type="hidden" name="forgot-post-bad" value="post-forgot-fail.html">\
+	 <table style="vertical-align:top;text-align:right"\
+          <tr>\
+           <td>User Name\
+            <input type="text" size="10" id="username" name="username" oninput="lwsgs_update()" onchange="lwsgs_update()"></td>\
+           <td>Password\
+            <input type="password" id="password" size="10" name="password" oninput="lwsgs_update()" onchange="lwsgs_update()"><div id="pw1"></div></td>\
+	     </tr><tr>\
+	   <td colspan="2" style="text-align:center"><input type="submit" id="login" name="login" value="Login" style="margin: 4px; padding: 2px; font-weight=bold;">\
+      &nbsp;<input type="submit" id="forgot" name="forgot" value="Forgot password" style="margin: 2px; padding: 2px">\
+           &nbsp;<input type="button" onclick="lwsgs_open_registration()" value="Sign up" style="margin: 2px; padding: 2px"></td>\
+          </tr>\
+         </table>\
+        </form>\
+       </div>\
+\
+       <div id="dlogout" style="display:none;text-align:right">\
+        <form action="lwsgs-logout" method="post" style="text-align:right">\
+         <input type="hidden" name="good" value="index.html">\
+         <table style="vertical-align:top;text-align:right">\
+          <tr><td><span id=grav></span></td>\
+ 	   <td style="text-align:center"><table><tr><td style="text-align:center">\
+		<a href="#" onclick="lwsgs_select_change(); event.preventDefault();">\
+		<span id="curuser"></span></a></td></tr><tr>\
+           <td style="text-align:center"><input type="submit" name="logout" value="Logout" style="margin: 2px; padding: 2px"></td>\
+          </tr></table></td></tr>\
+         </table>\
+        </form></div>\
+\
+	<div id="dregister" style="display:none">\
+	 <form action="lwsgs-login" method="post">\
+	  <input type="hidden" name="admin" value="needadmin/admin-login.html">\
+	  <input type="hidden" name="good" value="successful-login.html">\
+	  <input type="hidden" name="bad" value="failed-login.html">\
+	  <input type="hidden" name="reg-good" value="post-register-ok.html">\
+	  <input type="hidden" name="reg-bad" value="post-register-fail.html">\
+	  <input type="hidden" name="forgot-good" value="sent-forgot-ok.html">\
+	  <input type="hidden" name="forgot-bad" value="sent-forgot-fail.html">\
+	  <input type="hidden" name="forgot-post-good" value="post-forgot-ok.html">\
+	  <input type="hidden" name="forgot-post-bad" value="post-forgot-fail.html">\
+	  <table style="vertical-align:top;text-align:left">\
+	     <tr>\
+	      <td colspan=2 align=center>\
+		<span id="curuser"></span>\
+	<script>\
+		if (lwsgs_user)\
+			document.getElementById("curuser").innerHTML = "currently logged in as " + lwsgs_san(lwsgs_user) + "</br>";\
+	</script>\
+	       <b>Please enter your details to register</b>:\
+	      </td>\
+	     </tr>\
+	    <tr><td align=right>\
+	     User Name:</td>\
+	     <td><input type="text" size="10" id="rusername" name="username" oninput="lwsgs_rupdate(); lwsgs_check_user();">&nbsp;<span id=uchk></span></td>\
+	    </tr>\
+	    <tr>\
+	     <td align=right>Password:</td>\
+	     <td><input type="password" size="10" id="rpassword" name="password" oninput="lwsgs_rupdate()">&nbsp;<span id="rpw1"></span></td>\
+	    </tr>\
+	    <tr>\
+	    </tr>\
+	    <tr>\
+	     <td align=right><span id="pw2">Password (again):</span></td>\
+	     <td><input type="password" size="10" id="password2" name="password2" oninput="lwsgs_rupdate()">&nbsp;<span id="match"></span></td>\
+	    </tr>\
+	    <tr>\
+	     <td align=right>Email:</td>\
+	     <td><input type="email" size="10" id="email" name="email"\
+	          placeholder="me@example.com" oninput="lwsgs_rupdate(); lwsgs_check_email(\'email\')">&nbsp;<span id=echk></span></td>\
+	    </tr>\
+	    <tr>\
+	     <td colspan=2 align=center>\
+<input type="submit" id="register" name="register" value="Register" style="margin: 2px; padding: 2px">\
+<input type="submit" id="rforgot" name="forgot" value="Forgot Password" style="margin: 2px; padding: 2px;display: none">\
+<input type="button" id="cancel" name="cancel" value="Cancel" style="margin: 2px; padding: 2px;" onclick="lwsgs_cancel_registration()">\
+	     </td>\
+	    </tr>\
+         </table>\
+        </form>\
+       </div>\
+       \
+       <div id="dchange" style="display:none">\
+        <form action="lwsgs-change" method="post">\
+         <input type="hidden" id="cusername" name="username">\
+         <input type="hidden" name="admin" value="needadmin/admin-login.html">\
+         <input type="hidden" name="good" value="index.html">\
+         <input type="hidden" name="bad" value="failed-login.html">\
+         <input type="hidden" name="reg-good" value="post-register-ok.html">\
+         <input type="hidden" name="reg-bad" value="post-register-fail.html">\
+         <input type="hidden" name="forgot-good" value="sent-forgot-ok.html">\
+         <input type="hidden" name="forgot-bad" value="sent-forgot-fail.html">\
+         <input type="hidden" name="forgot-post-good" value="post-forgot-ok.html">\
+         <input type="hidden" name="forgot-post-bad" value="post-forgot-fail.html">\
+         <table style="vertical-align:top;text-align:left">\
+	     <tr>\
+	      <td colspan=2 align=center>\
+		<span id="ccuruser"></span>\
+	<script>\
+		if (lwsgs_user)\
+			document.getElementById("ccuruser").innerHTML =\
+			  "<span class=\"gstitle\">Login settings for " +\
+			  lwsgs_san(lwsgs_user) + "</span></br>";\
+	</script>\
+	       <b>Please enter your details to change</b>:\
+	      </td>\
+	     </tr>\
+	    <tr><td align=right id="ccurpw_name">\
+	     Current Password:</td>\
+	     <td><input type="password" size="10" id="ccurpw" name="curpw"\
+	          oninput="lwsgs_cupdate();">&nbsp;<span id=cuchk></span></td>\
+	    </tr>\
+	    <tr>\
+	     <td align=right>Password:</td>\
+	     <td><input type="password" size="10" id="cpassword" name="password"\
+	          oninput="lwsgs_cupdate()">&nbsp;<span id="cpw1"></span></td>\
+	    </tr>\
+	    <tr>\
+	     <td align=right><span id="pw2">Password (again)</span></td>\
+	     <td><input type="password" size="10" id="cpassword2" name="password2"\
+	          oninput="lwsgs_cupdate()">&nbsp;<span id="cmatch"></span></td>\
+	    </tr>\
+	<!-- not supported yet\
+	    <tr>\
+	     <td align=right id="cemail_name">Email:</td>\
+	     <td><input type="email" size="10" id="cemail" name="email"\
+	     	  placeholder="?" oninput="lwsgs_cupdate(); lwsgs_check_email(\'cemail\')">\
+	     	  &nbsp;<span id=cechk></span></td>\
+	    </tr> -->\
+	    <tr>\
+	     <td colspan=2 align=center>\
+	      <input type="submit" id="change" name="change"\
+	       value="Change" style="margin: 6px; padding: 6px">\
+	      <input type="submit" id="cforgot" name="forgot"\
+	       value="Forgot Password" style="margin: 6px; padding: 6px;display: none">\
+	      <input type="button" id="cancel" name="cancel"\
+	       value="Cancel" style="margin: 6px; padding: 6px;"\
+	       onclick="lwsgs_cancel_registration()">\
+	     </td>\
+	    </tr>\
+	    <tr>\
+	     <td colspan=2>\
+	      <input type="checkbox" id="showdel" name="showdel"\
+	       onchange="lwsgs_cupdate();"> Show Delete&nbsp;\
+	      <input type="submit" id="delete" name="delete" \
+	       value="Delete Account" style="margin: 6px; padding: 6px;display: none">\
+	     </td>\
+	    </tr>\
+         </table>\
+        </form>\
+       </div>\
+       \
+       <div id="dadmin" style="display:none">\
+         Admin settings TBD\
+       </div>\
+';
+
+/*-- 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<<t|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<<r%32,n[(r+64>>>9<<4)+14]=r;var e,i,a,h,d,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,h=v,d=m,l=o(l,g,v,m,n[e],7,-680876936),m=o(m,l,g,v,n[e+1],12,-389564586),v=o(v,m,l,g,n[e+2],17,606105819),g=o(g,v,m,l,n[e+3],22,-1044525330),l=o(l,g,v,m,n[e+4],7,-176418897),m=o(m,l,g,v,n[e+5],12,1200080426),v=o(v,m,l,g,n[e+6],17,-1473231341),g=o(g,v,m,l,n[e+7],22,-45705983),l=o(l,g,v,m,n[e+8],7,1770035416),m=o(m,l,g,v,n[e+9],12,-1958414417),v=o(v,m,l,g,n[e+10],17,-42063),g=o(g,v,m,l,n[e+11],22,-1990404162),l=o(l,g,v,m,n[e+12],7,1804603682),m=o(m,l,g,v,n[e+13],12,-40341101),v=o(v,m,l,g,n[e+14],17,-1502002290),g=o(g,v,m,l,n[e+15],22,1236535329),l=u(l,g,v,m,n[e+1],5,-165796510),m=u(m,l,g,v,n[e+6],9,-1069501632),v=u(v,m,l,g,n[e+11],14,643717713),g=u(g,v,m,l,n[e],20,-373897302),l=u(l,g,v,m,n[e+5],5,-701558691),m=u(m,l,g,v,n[e+10],9,38016083),v=u(v,m,l,g,n[e+15],14,-660478335),g=u(g,v,m,l,n[e+4],20,-405537848),l=u(l,g,v,m,n[e+9],5,568446438),m=u(m,l,g,v,n[e+14],9,-1019803690),v=u(v,m,l,g,n[e+3],14,-187363961),g=u(g,v,m,l,n[e+8],20,1163531501),l=u(l,g,v,m,n[e+13],5,-1444681467),m=u(m,l,g,v,n[e+2],9,-51403784),v=u(v,m,l,g,n[e+7],14,1735328473),g=u(g,v,m,l,n[e+12],20,-1926607734),l=c(l,g,v,m,n[e+5],4,-378558),m=c(m,l,g,v,n[e+8],11,-2022574463),v=c(v,m,l,g,n[e+11],16,1839030562),g=c(g,v,m,l,n[e+14],23,-35309556),l=c(l,g,v,m,n[e+1],4,-1530992060),m=c(m,l,g,v,n[e+4],11,1272893353),v=c(v,m,l,g,n[e+7],16,-155497632),g=c(g,v,m,l,n[e+10],23,-1094730640),l=c(l,g,v,m,n[e+13],4,681279174),m=c(m,l,g,v,n[e],11,-358537222),v=c(v,m,l,g,n[e+3],16,-722521979),g=c(g,v,m,l,n[e+6],23,76029189),l=c(l,g,v,m,n[e+9],4,-640364487),m=c(m,l,g,v,n[e+12],11,-421815835),v=c(v,m,l,g,n[e+15],16,530742520),g=c(g,v,m,l,n[e+2],23,-995338651),l=f(l,g,v,m,n[e],6,-198630844),m=f(m,l,g,v,n[e+7],10,1126891415),v=f(v,m,l,g,n[e+14],15,-1416354905),g=f(g,v,m,l,n[e+5],21,-57434055),l=f(l,g,v,m,n[e+12],6,1700485571),m=f(m,l,g,v,n[e+3],10,-1894986606),v=f(v,m,l,g,n[e+10],15,-1051523),g=f(g,v,m,l,n[e+1],21,-2054922799),l=f(l,g,v,m,n[e+8],6,1873313359),m=f(m,l,g,v,n[e+15],10,-30611744),v=f(v,m,l,g,n[e+6],15,-1560198380),g=f(g,v,m,l,n[e+13],21,1309151649),l=f(l,g,v,m,n[e+4],6,-145523070),m=f(m,l,g,v,n[e+11],10,-1120210379),v=f(v,m,l,g,n[e+2],15,718787259),g=f(g,v,m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,h),m=t(m,d);return[l,g,v,m]}function a(n){var t,r="";for(t=0;t<32*n.length;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function h(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;for(t=0;t<8*n.length;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function d(n){return a(i(h(n),8*n.length))}function l(n,t){var r,e,o=h(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>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<n.length;r+=1)t=n.charCodeAt(r),o+=e.charAt(t>>>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";
+	}
+}
+
+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 = 
+				"<b style=\"color:green\">\u2713</b>";
+		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 =
+				"<span style=\"color: red\">\u2718 <b>Passwords do not match</b></span>";
+		} else
+			document.getElementById('match').innerHTML =
+				"<span style=\"color: gray\">\u2718 Passwords do not match</span>";
+
+		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 = "<b style=\"color:green\">\u2713</b>";
+		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') {
+		if (document.getElementById('rusername').value)
+			document.getElementById('uchk').innerHTML = "<b style=\"color:green\">\u2713</b>";
+		else
+			document.getElementById('uchk').innerHTML = "";
+	} else {
+		document.getElementById('uchk').innerHTML = "<b style=\"color:red\">\u2718 Already registered</b>";
+		en_forgot = 1;
+	}
+
+	if (lwsgs_email_check === '0') {
+		if (document.getElementById('email').value)
+			document.getElementById('echk').innerHTML = "<b style=\"color:green\">\u2713</b>";
+		else
+			document.getElementById('echk').innerHTML = "";
+	} else {
+		document.getElementById('echk').innerHTML = "<b style=\"color:red\">\u2718 Already registered</b>";
+		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 = "<b style=\"color:red\">\u2718</b>";
+		} 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 = "<b style=\"color:green\">\u2713</b>";
+		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 =
+				"<span style=\"color: red\">\u2718 <b>Passwords do not match</b></span>";
+		} else
+			document.getElementById('cmatch').innerHTML = "<span style=\"color: gray\">\u2718 Passwords do not match</span>";
+
+		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
+		if (document.getElementById('cpassword').value.length)
+			document.getElementById('cpw1').innerHTML = "<b style=\"color:green\">\u2713</b>";
+		else
+			document.getElementById('cpw1').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 = "<b style=\"color:green\">\u2713</b>";
+			else
+				document.getElementById('cechk').innerHTML = "";
+		} else {
+			document.getElementById('cechk').innerHTML = "<b style=\"color:red\">\u2718 Already registered</b>";
+			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 lwsgs_initial()
+{
+	document.getElementById('lwsgs').innerHTML = lwsgs_html;
+	if (lwsgs_email)
+		document.getElementById('grav').innerHTML =
+			"<img src=\"https://www.gravatar.com/avatar/" + md5(lwsgs_email) +
+			"?d=identicon\">";
+	//if (lwsgs_email)
+		//document.getElementById('cemail').placeholder = lwsgs_email;
+	document.getElementById('cusername').value = lwsgs_user;
+	lwsgs_update();
+	lwsgs_cupdate();
+}
diff --git a/plugins/generic-sessions/assets/md5.min.js b/plugins/generic-sessions/assets/md5.min.js
new file mode 100644
index 00000000..4bd9de1e
--- /dev/null
+++ b/plugins/generic-sessions/assets/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<<t|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<<r%32,n[(r+64>>>9<<4)+14]=r;var e,i,a,h,d,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,h=v,d=m,l=o(l,g,v,m,n[e],7,-680876936),m=o(m,l,g,v,n[e+1],12,-389564586),v=o(v,m,l,g,n[e+2],17,606105819),g=o(g,v,m,l,n[e+3],22,-1044525330),l=o(l,g,v,m,n[e+4],7,-176418897),m=o(m,l,g,v,n[e+5],12,1200080426),v=o(v,m,l,g,n[e+6],17,-1473231341),g=o(g,v,m,l,n[e+7],22,-45705983),l=o(l,g,v,m,n[e+8],7,1770035416),m=o(m,l,g,v,n[e+9],12,-1958414417),v=o(v,m,l,g,n[e+10],17,-42063),g=o(g,v,m,l,n[e+11],22,-1990404162),l=o(l,g,v,m,n[e+12],7,1804603682),m=o(m,l,g,v,n[e+13],12,-40341101),v=o(v,m,l,g,n[e+14],17,-1502002290),g=o(g,v,m,l,n[e+15],22,1236535329),l=u(l,g,v,m,n[e+1],5,-165796510),m=u(m,l,g,v,n[e+6],9,-1069501632),v=u(v,m,l,g,n[e+11],14,643717713),g=u(g,v,m,l,n[e],20,-373897302),l=u(l,g,v,m,n[e+5],5,-701558691),m=u(m,l,g,v,n[e+10],9,38016083),v=u(v,m,l,g,n[e+15],14,-660478335),g=u(g,v,m,l,n[e+4],20,-405537848),l=u(l,g,v,m,n[e+9],5,568446438),m=u(m,l,g,v,n[e+14],9,-1019803690),v=u(v,m,l,g,n[e+3],14,-187363961),g=u(g,v,m,l,n[e+8],20,1163531501),l=u(l,g,v,m,n[e+13],5,-1444681467),m=u(m,l,g,v,n[e+2],9,-51403784),v=u(v,m,l,g,n[e+7],14,1735328473),g=u(g,v,m,l,n[e+12],20,-1926607734),l=c(l,g,v,m,n[e+5],4,-378558),m=c(m,l,g,v,n[e+8],11,-2022574463),v=c(v,m,l,g,n[e+11],16,1839030562),g=c(g,v,m,l,n[e+14],23,-35309556),l=c(l,g,v,m,n[e+1],4,-1530992060),m=c(m,l,g,v,n[e+4],11,1272893353),v=c(v,m,l,g,n[e+7],16,-155497632),g=c(g,v,m,l,n[e+10],23,-1094730640),l=c(l,g,v,m,n[e+13],4,681279174),m=c(m,l,g,v,n[e],11,-358537222),v=c(v,m,l,g,n[e+3],16,-722521979),g=c(g,v,m,l,n[e+6],23,76029189),l=c(l,g,v,m,n[e+9],4,-640364487),m=c(m,l,g,v,n[e+12],11,-421815835),v=c(v,m,l,g,n[e+15],16,530742520),g=c(g,v,m,l,n[e+2],23,-995338651),l=f(l,g,v,m,n[e],6,-198630844),m=f(m,l,g,v,n[e+7],10,1126891415),v=f(v,m,l,g,n[e+14],15,-1416354905),g=f(g,v,m,l,n[e+5],21,-57434055),l=f(l,g,v,m,n[e+12],6,1700485571),m=f(m,l,g,v,n[e+3],10,-1894986606),v=f(v,m,l,g,n[e+10],15,-1051523),g=f(g,v,m,l,n[e+1],21,-2054922799),l=f(l,g,v,m,n[e+8],6,1873313359),m=f(m,l,g,v,n[e+15],10,-30611744),v=f(v,m,l,g,n[e+6],15,-1560198380),g=f(g,v,m,l,n[e+13],21,1309151649),l=f(l,g,v,m,n[e+4],6,-145523070),m=f(m,l,g,v,n[e+11],10,-1120210379),v=f(v,m,l,g,n[e+2],15,718787259),g=f(g,v,m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,h),m=t(m,d);return[l,g,v,m]}function a(n){var t,r="";for(t=0;t<32*n.length;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function h(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;for(t=0;t<8*n.length;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function d(n){return a(i(h(n),8*n.length))}function l(n,t){var r,e,o=h(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>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<n.length;r+=1)t=n.charCodeAt(r),o+=e.charAt(t>>>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/plugins/generic-sessions/assets/post-forgot-fail.html b/plugins/generic-sessions/assets/post-forgot-fail.html
new file mode 100644
index 00000000..ead3d13e
--- /dev/null
+++ b/plugins/generic-sessions/assets/post-forgot-fail.html
@@ -0,0 +1,5 @@
+<html>
+Sorry, something went wrong.
+
+Click <a href="../">here</a> to continue.
+</html>
diff --git a/plugins/generic-sessions/assets/post-forgot-ok.html b/plugins/generic-sessions/assets/post-forgot-ok.html
new file mode 100644
index 00000000..3e8e9cf5
--- /dev/null
+++ b/plugins/generic-sessions/assets/post-forgot-ok.html
@@ -0,0 +1,6 @@
+<html>
+This is a one-time password recovery login.
+
+Please click <a href="./">here</a> and click your username at the top to reset your password.
+</html>
+
diff --git a/plugins/generic-sessions/assets/post-register-fail.html b/plugins/generic-sessions/assets/post-register-fail.html
new file mode 100644
index 00000000..063c3c50
--- /dev/null
+++ b/plugins/generic-sessions/assets/post-register-fail.html
@@ -0,0 +1 @@
+Registration failed, sorry
diff --git a/plugins/generic-sessions/assets/post-register-ok.html b/plugins/generic-sessions/assets/post-register-ok.html
new file mode 100644
index 00000000..2d150358
--- /dev/null
+++ b/plugins/generic-sessions/assets/post-register-ok.html
@@ -0,0 +1,27 @@
+<html>
+ <head>
+  <script src="lwsgs.js"></script>
+ </head>
+ <body>
+  <table>
+    <tr>
+     <td colspan=2 align=center>
+      <img src="lwsgs-logo.png">
+     </td>
+    </tr>
+    <tr>
+     <td>
+      Your registration as <span id="u"></span> is accepted,<br>
+      you will receive an email shortly with instructions<br>
+      to verify and enable the account for normal use.<br><br>
+      The link is only valid for an hour, after that if it has<br>
+      not been verified your account will be deleted.
+     </td>
+    </tr>
+   </table>
+  </body>
+ <script>
+	document.getElementById('u').innerHTML = "<b>" + lwsgs_san(lwsgs_user) + "</b>";
+ </script>
+</html>
+
diff --git a/plugins/generic-sessions/assets/post-verify-fail.html b/plugins/generic-sessions/assets/post-verify-fail.html
new file mode 100644
index 00000000..d1d89ca5
--- /dev/null
+++ b/plugins/generic-sessions/assets/post-verify-fail.html
@@ -0,0 +1,20 @@
+<html>
+ <head>
+  <script src="lwsgs.js"></script>
+ </head>
+ <body>
+  <table>
+    <tr>
+     <td colspan=2 align=center>
+      <img src="lwsws-logo.png">
+     </td>
+    </tr>
+    <tr>
+     <td>
+	Sorry, the link was invalid.
+     </td>
+    </tr>
+   </table>
+  </body>
+</html>
+
diff --git a/plugins/generic-sessions/assets/post-verify-ok.html b/plugins/generic-sessions/assets/post-verify-ok.html
new file mode 100644
index 00000000..e968f6a7
--- /dev/null
+++ b/plugins/generic-sessions/assets/post-verify-ok.html
@@ -0,0 +1,25 @@
+<html>
+ <head>
+  <script src="lwsgs.js"></script>
+ </head>
+ <body>
+  <table>
+    <tr>
+     <td colspan=2 align=center>
+      <img src="lwsgs-logo.png">
+     </td>
+    </tr>
+    <tr>
+     <td>
+        Thanks for signing up, your registration as <span id="u"></span> is verified.<br>
+	<br>
+	Click <a href="/lwsgs">here</a> to continue.
+     </td>
+    </tr>
+   </table>
+  </body>
+ <script>
+	document.getElementById('u').innerHTML = "<b>" + san(lwsgs_user) + "</b>";
+ </script>
+</html>
+
diff --git a/plugins/generic-sessions/assets/seats.jpg b/plugins/generic-sessions/assets/seats.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5bed40d919872359f2fcc00a8430e7dcfabaab4a
GIT binary patch
literal 122754
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
Kf%~`m|2F}BW(*ww

literal 0
HcmV?d00001

diff --git a/plugins/generic-sessions/assets/sent-forgot-fail.html b/plugins/generic-sessions/assets/sent-forgot-fail.html
new file mode 100644
index 00000000..ead3d13e
--- /dev/null
+++ b/plugins/generic-sessions/assets/sent-forgot-fail.html
@@ -0,0 +1,5 @@
+<html>
+Sorry, something went wrong.
+
+Click <a href="../">here</a> to continue.
+</html>
diff --git a/plugins/generic-sessions/assets/sent-forgot-ok.html b/plugins/generic-sessions/assets/sent-forgot-ok.html
new file mode 100644
index 00000000..83df7510
--- /dev/null
+++ b/plugins/generic-sessions/assets/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/plugins/generic-sessions/assets/successful-login.html b/plugins/generic-sessions/assets/successful-login.html
new file mode 100644
index 00000000..dfc25cf7
--- /dev/null
+++ b/plugins/generic-sessions/assets/successful-login.html
@@ -0,0 +1,4 @@
+<html>
+This is an example destination that will appear after successful non-Admin login
+</html>
+
diff --git a/plugins/generic-sessions/handlers.c b/plugins/generic-sessions/handlers.c
new file mode 100644
index 00000000..bd00c2b4
--- /dev/null
+++ b/plugins/generic-sessions/handlers.c
@@ -0,0 +1,598 @@
+/*
+ * ws protocol handler plugin for "generic sessions"
+ *
+ * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation:
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ */
+
+#include "private-lwsgs.h"
+
+/* 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];
+	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)
+		goto verf_fail;
+
+	if (strncmp(cookie, "token=", 6))
+		goto verf_fail;
+
+	u.username[0] = '\0';
+	snprintf(s, sizeof(s) - 1,
+		 "select username,email,verified from users where token = '%s';",
+		 lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
+	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
+	    SQLITE_OK) {
+		lwsl_err("Unable to lookup token: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+		goto verf_fail;
+	}
+
+	if (!u.username[0] || u.verified != 1) {
+		lwsl_notice("verify token doesn't map to unverified user\n");
+		goto verf_fail;
+	}
+
+	lwsl_notice("Verifying %s\n", u.username);
+	snprintf(s, sizeof(s) - 1,
+		 "update users set verified=%d where username='%s';",
+		 LWSGS_VERIFIED_ACCEPTED,
+		 lws_sql_purify(esc, u.username, sizeof(esc) - 1));
+	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
+	    SQLITE_OK) {
+		lwsl_err("Unable to lookup token: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+
+		goto verf_fail;
+	}
+
+	lwsl_notice("deleting account\n");
+
+	a.event = LWSGSE_CREATED;
+	a.username = u.username;
+	a.email = u.email;
+	lws_callback_vhost_protocols(wsi, LWS_CALLBACK_GS_EVENT, &a, 0);
+
+	snprintf(pss->onward, sizeof(pss->onward),
+		 "%s/post-verify-ok.html", vhd->email_confirm_url);
+
+	pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs;
+
+	pss->delete_session.id[0] = '\0';
+	lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
+
+	/* we need to create a new, authorized session */
+
+	if (lwsgs_new_session_id(vhd, &pss->login_session, u.username,
+				 pss->login_expires))
+		goto verf_fail;
+
+	lwsl_notice("Creating new session: %s, redir to %s\n",
+		    pss->login_session.id, pss->onward);
+
+	return 0;
+
+verf_fail:
+	pss->delete_session.id[0] = '\0';
+	lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
+	pss->login_expires = 0;
+
+	snprintf(pss->onward, sizeof(pss->onward), "%s/post-verify-fail.html",
+		 vhd->email_confirm_url);
+
+	return 1;
+}
+
+/* handle forgot password confirmation links */
+
+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];
+	struct lwsgs_user u;
+	const char *a;
+
+	a = lws_get_urlarg_by_name(wsi, "token=", cookie, sizeof(cookie));
+	if (!a)
+		goto forgot_fail;
+
+	u.username[0] = '\0';
+	snprintf(s, sizeof(s) - 1,
+		 "select username,verified from users where verified=%d and "
+		 "token = '%s' and token_time != 0;",
+		 LWSGS_VERIFIED_ACCEPTED,
+		 lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
+	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
+	    SQLITE_OK) {
+		lwsl_err("Unable to lookup token: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+
+		goto forgot_fail;
+	}
+
+	if (!u.username[0]) {
+		puts(s);
+		lwsl_notice("forgot token doesn't map to verified user\n");
+		goto forgot_fail;
+	}
+
+	/* mark user as having validated forgot flow just now */
+
+	snprintf(s, sizeof(s) - 1,
+		 "update users set token_time=0,last_forgot_validated=%lu "
+		 "where username='%s';",
+		 (unsigned long)lws_now_secs(),
+		 lws_sql_purify(esc, u.username, sizeof(esc) - 1));
+
+	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
+	    SQLITE_OK) {
+		lwsl_err("Unable to lookup token: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+		goto forgot_fail;
+	}
+
+	a = lws_get_urlarg_by_name(wsi, "good=", cookie, sizeof(cookie));
+	if (!a)
+		a = "broken-forget-post-good-url";
+
+	snprintf(pss->onward, sizeof(pss->onward),
+		 "%s/%s", vhd->email_confirm_url, a);
+
+	pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs;
+
+	pss->delete_session.id[0] = '\0';
+	lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
+
+	/* we need to create a new, authorized session */
+	if (lwsgs_new_session_id(vhd, &pss->login_session,
+				 u.username,
+				 pss->login_expires))
+		goto forgot_fail;
+
+	lwsl_notice("Creating new session: %s, redir to %s\n",
+		    pss->login_session.id, pss->onward);
+
+	return 0;
+
+forgot_fail:
+	pss->delete_session.id[0] = '\0';
+	lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
+	pss->login_expires = 0;
+
+	a = lws_get_urlarg_by_name(wsi, "bad=", cookie, sizeof(cookie));
+	if (!a)
+		a = "broken-forget-post-bad-url";
+
+	snprintf(pss->onward, sizeof(pss->onward), "%s/%s",
+		 vhd->email_confirm_url, a);
+
+	return 1;
+}
+
+/* support dynamic username / email checking */
+
+int
+lwsgs_handler_check(struct per_vhost_data__gs *vhd,
+		    struct lws *wsi, struct per_session_data__gs *pss)
+{
+	static const char * const colname[] = { "username", "email" };
+	char cookie[1024], s[256], esc[50], *pc;
+	unsigned char *p, *start, *end, buffer[LWS_PRE + 256];
+	struct lwsgs_user u;
+	int n;
+
+	/*
+	 * 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, '=');
+	if (!pc) {
+		lwsl_notice("cookie has no =\n");
+		goto reply;
+	}
+	pc++;
+
+	/* admin user cannot be registered in user db */
+	if (!strcmp(vhd->admin_user, pc)) {
+		u.username[0] = 'a';
+		goto reply;
+	}
+
+	snprintf(s, sizeof(s) - 1,
+		 "select username, email from users where %s = '%s';",
+		 colname[n], lws_sql_purify(esc, pc, sizeof(esc) - 1));
+	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
+	    SQLITE_OK) {
+		lwsl_err("Unable to lookup token: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+		goto reply;
+	}
+
+reply:
+	s[0] = '0' + !!u.username[0];
+	p = buffer + LWS_PRE;
+	start = p;
+	end = p + sizeof(buffer) - LWS_PRE;
+
+	if (lws_add_http_header_status(wsi, 200, &p, end))
+		return -1;
+	if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
+					 (unsigned char *)"text/plain", 10,
+					 &p, end))
+		return -1;
+
+	if (lws_add_http_header_content_length(wsi, 1, &p, end))
+		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 %d\n", n, (p - start));
+		return -1;
+	}
+	n = lws_write(wsi, (unsigned char *)s, 1, LWS_WRITE_HTTP);
+	if (n != 1)
+		return -1;
+
+	return 0;
+}
+
+/* handle forgot password confirmation links */
+
+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];
+	struct lwsgs_user u;
+	lwsgw_hash sid;
+	int n = 0;
+
+	/* see if he's logged in */
+	username[0] = '\0';
+	if (!lwsgs_get_sid_from_wsi(wsi, &sid)) {
+		u.username[0] = '\0';
+		if (!lwsgs_lookup_session(vhd, &sid, username, sizeof(username))) {
+			n = 1; /* yes, logged in */
+			if (lwsgs_lookup_user(vhd, username, &u))
+				return 1;
+
+			/* did a forgot pw ? */
+			if (u.last_forgot_validated > lws_now_secs() - 300)
+				n |= LWSGS_AUTH_FORGOT_FLOW;
+		}
+	}
+
+	/* if he just did forgot pw flow, don't need old pw */
+	if (!(n & (LWSGS_AUTH_FORGOT_FLOW | 1))) {
+		/* otherwise user:pass must be right */
+		if (lwsgs_check_credentials(vhd,
+			   lws_spa_get_string(pss->spa, FGS_USERNAME),
+			   lws_spa_get_string(pss->spa, FGS_CURPW))) {
+			lwsl_notice("credentials bad\n");
+			return 1;
+		}
+
+		strcpy(u.username, lws_spa_get_string(pss->spa, FGS_USERNAME));
+	}
+
+	/* does he want to delete his account? */
+
+	if (lws_spa_get_length(pss->spa, FGS_DELETE)) {
+		struct lws_gs_event_args a;
+
+		lwsl_notice("deleting account\n");
+
+		a.event = LWSGSE_DELETED;
+		a.username = u.username;
+		a.email = "";
+		lws_callback_vhost_protocols(wsi, LWS_CALLBACK_GS_EVENT, &a, 0);
+
+		snprintf(s, sizeof(s) - 1,
+			 "delete from users where username='%s';"
+			 "delete from sessions where username='%s';",
+			 lws_sql_purify(esc, u.username, sizeof(esc) - 1),
+			 lws_sql_purify(esc, u.username, sizeof(esc) - 1));
+		goto sql;
+	}
+
+	if (lwsgs_hash_password(vhd, lws_spa_get_string(pss->spa, FGS_PASSWORD), &u))
+		return 1;
+
+	lwsl_notice("updating password hash\n");
+
+	snprintf(s, sizeof(s) - 1,
+		 "update users set pwhash='%s', pwsalt='%s', "
+		 "last_forgot_validated=0 where username='%s';",
+		 u.pwhash.id, u.pwsalt.id,
+		 lws_sql_purify(esc, u.username, sizeof(esc) - 1));
+
+sql:
+	if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
+		lwsl_err("Unable to update pw hash: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd,
+			     struct lws *wsi,
+			     struct per_session_data__gs *pss)
+{
+	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];
+	struct lwsgs_user u;
+	lwsgw_hash hash;
+	unsigned char sid_rand[20];
+	int n;
+
+	lwsl_notice("FORGOT %s %s\n",
+		    lws_spa_get_string(pss->spa, FGS_USERNAME),
+		    lws_spa_get_string(pss->spa, FGS_EMAIL));
+
+	if (!lws_spa_get_string(pss->spa, FGS_USERNAME) &&
+	    !lws_spa_get_string(pss->spa, FGS_EMAIL)) {
+		lwsl_err("Form must provide either "
+			  "username or email\n");
+		return -1;
+	}
+
+	if (!lws_spa_get_string(pss->spa, FGS_FORGOT_GOOD) ||
+	    !lws_spa_get_string(pss->spa, FGS_FORGOT_BAD) ||
+	    !lws_spa_get_string(pss->spa, FGS_FORGOT_POST_GOOD) ||
+	    !lws_spa_get_string(pss->spa, FGS_FORGOT_POST_BAD)) {
+		lwsl_err("Form must provide reg-good "
+			  "and reg-bad (and post-*)"
+			  "targets\n");
+		return -1;
+	}
+
+	u.username[0] = '\0';
+	if (lws_spa_get_string(pss->spa, FGS_USERNAME))
+		snprintf(s, sizeof(s) - 1,
+		 "select username,email "
+		 "from users where username = '%s';",
+		 lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME),
+				 sizeof(esc) - 1));
+	else
+		snprintf(s, sizeof(s) - 1,
+		 "select username,email "
+		 "from users where email = '%s';",
+		 lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc) - 1));
+	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
+	    SQLITE_OK) {
+		lwsl_err("Unable to lookup token: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+		return 1;
+	}
+	if (!u.username[0]) {
+		lwsl_err("No match found %s\n", s);
+		return 1;
+	}
+
+	lws_get_peer_simple(wsi, pss->ip, sizeof(pss->ip));
+	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);
+	n = snprintf(s, sizeof(s),
+		"From: Forgot Password Assistant Noreply <%s>\n"
+		"To: %s <%s>\n"
+		  "Subject: Password reset request\n"
+		  "\n"
+		  "Hello, %s\n\n"
+		  "We received a password reset request from IP %s for this email,\n"
+		  "to confirm you want to do that, please click the link below.\n\n",
+		lws_sql_purify(esc, vhd->email.email_from, sizeof(esc) - 1),
+		lws_sql_purify(esc1, u.username, sizeof(esc1) - 1),
+		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));
+	snprintf(s + n, sizeof(s) -n,
+		  "%s/lwsgs-forgot?token=%s"
+		   "&good=%s"
+		   "&bad=%s\n\n"
+		  "If this request is unexpected, please ignore it and\n"
+		  "no further action will be taken.\n\n"
+		"If you have any questions or concerns about this\n"
+		"automated email, you can contact a real person at\n"
+		"%s.\n"
+		"\n.\n",
+		vhd->email_confirm_url, hash.id,
+		lws_urlencode(esc1,
+			     lws_spa_get_string(pss->spa, FGS_FORGOT_POST_GOOD),
+			     sizeof(esc1) - 1),
+		lws_urlencode(esc3,
+			      lws_spa_get_string(pss->spa, FGS_FORGOT_POST_BAD),
+			      sizeof(esc3) - 1),
+		vhd->email_contact_person);
+
+	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;
+	}
+
+	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;
+	}
+
+	return 0;
+}
+
+int
+lwsgs_handler_register_form(struct per_vhost_data__gs *vhd,
+			     struct lws *wsi,
+			     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 s[LWSGS_EMAIL_CONTENT_SIZE];
+	unsigned char sid_rand[20];
+	struct lwsgs_user u;
+	lwsgw_hash hash;
+
+	lwsl_notice("REGISTER %s %s %s\n",
+			lws_spa_get_string(pss->spa, FGS_USERNAME),
+			lws_spa_get_string(pss->spa, FGS_PASSWORD),
+			lws_spa_get_string(pss->spa, FGS_EMAIL));
+	if (lwsgs_get_sid_from_wsi(wsi,
+	    &pss->login_session))
+		return 1;
+
+	lws_get_peer_simple(wsi, pss->ip, sizeof(pss->ip));
+	lwsl_notice("IP=%s\n", pss->ip);
+
+	if (!lws_spa_get_string(pss->spa, FGS_REG_GOOD) ||
+	    !lws_spa_get_string(pss->spa, FGS_REG_BAD)) {
+		lwsl_info("Form must provide reg-good and reg-bad targets\n");
+		return -1;
+	}
+
+	/* admin user cannot be registered in user db */
+	if (!strcmp(vhd->admin_user,
+		    lws_spa_get_string(pss->spa, FGS_USERNAME)))
+		return 1;
+
+	if (!lwsgs_lookup_user(vhd,
+			lws_spa_get_string(pss->spa, FGS_USERNAME), &u)) {
+		lwsl_notice("user %s already registered\n",
+			    lws_spa_get_string(pss->spa, FGS_USERNAME));
+		return 1;
+	}
+
+	u.username[0] = '\0';
+	snprintf(s, sizeof(s) - 1, "select username, email from users where email = '%s';",
+		 lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_EMAIL),
+		 sizeof(esc) - 1));
+
+	if (sqlite3_exec(vhd->pdb, s,
+			 lwsgs_lookup_callback_user, &u, NULL) != SQLITE_OK) {
+		lwsl_err("Unable to lookup token: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+		return 1;
+	}
+
+	if (u.username[0]) {
+		lwsl_notice("email %s already in use\n",
+			    lws_spa_get_string(pss->spa, FGS_USERNAME));
+		return 1;
+	}
+
+	if (lwsgs_hash_password(vhd, lws_spa_get_string(pss->spa, FGS_PASSWORD),
+			        &u)) {
+		lwsl_err("Password hash failed\n");
+		return 1;
+	}
+
+	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);
+
+	snprintf((char *)buffer, sizeof(buffer) - 1,
+		 "insert into users(username,"
+		 " creation_time, ip, email, verified,"
+		 " pwhash, pwsalt, token, last_forgot_validated)"
+		 " values ('%s', %lu, '%s', '%s', 0,"
+		 " '%s', '%s', '%s', 0);",
+		lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc) - 1),
+		(unsigned long)lws_now_secs(),
+		lws_sql_purify(esc1, pss->ip, sizeof(esc1) - 1),
+		lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
+		u.pwhash.id, u.pwsalt.id, hash.id);
+
+	if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL, NULL, NULL) != SQLITE_OK) {
+		lwsl_err("Unable to insert user: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+		return 1;
+	}
+
+	snprintf(s, sizeof(s),
+		"From: Noreply <%s>\n"
+		"To: %s <%s>\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"
+		  "%s/lwsgs-confirm?token=%s\n\n"
+		  "If this request is unexpected, please ignore it and\n"
+		  "no further action will be taken.\n\n"
+		"If you have any questions or concerns about this\n"
+		"automated email, you can contact a real person at\n"
+		"%s.\n"
+		"\n.\n",
+		lws_sql_purify(esc, vhd->email.email_from, sizeof(esc) - 1),
+		lws_sql_purify(esc1, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc1) - 1),
+		lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
+		lws_sql_purify(esc3, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc3) - 1),
+		lws_sql_purify(esc4, pss->ip, sizeof(esc4) - 1),
+		vhd->email_confirm_url, hash.id,
+		vhd->email_contact_person);
+
+	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));
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/plugins/generic-sessions/private-lwsgs.h b/plugins/generic-sessions/private-lwsgs.h
new file mode 100644
index 00000000..cb408ae8
--- /dev/null
+++ b/plugins/generic-sessions/private-lwsgs.h
@@ -0,0 +1,161 @@
+/*
+ * ws protocol handler plugin for "generic sessions"
+ *
+ * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation:
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ */
+
+#define LWS_DLL
+#define LWS_INTERNAL
+#include "../lib/libwebsockets.h"
+
+#include <sqlite3.h>
+#include <string.h>
+
+#define LWSGS_VERIFIED_ACCEPTED 100
+
+enum {
+	FGS_USERNAME,
+	FGS_PASSWORD,
+	FGS_PASSWORD2,
+	FGS_EMAIL,
+	FGS_REGISTER,
+	FGS_GOOD,
+	FGS_BAD,
+	FGS_REG_GOOD,
+	FGS_REG_BAD,
+	FGS_ADMIN,
+	FGS_FORGOT,
+	FGS_FORGOT_GOOD,
+	FGS_FORGOT_BAD,
+	FGS_FORGOT_POST_GOOD,
+	FGS_FORGOT_POST_BAD,
+	FGS_CHANGE,
+	FGS_CURPW,
+	FGS_DELETE,
+};
+
+struct lwsgs_user {
+	char username[32];
+	char ip[16];
+	lwsgw_hash pwhash;
+	lwsgw_hash pwsalt;
+	lwsgw_hash token;
+	time_t created;
+	time_t last_forgot_validated;
+	char email[100];
+	int verified;
+};
+
+struct per_vhost_data__gs {
+	struct lws_email email;
+	struct lws_context *context;
+	char session_db[256];
+	char admin_user[32];
+	char confounder[32];
+	char email_contact_person[128];
+	char email_title[128];
+	char email_template[128];
+	char email_confirm_url[128];
+	lwsgw_hash admin_password_sha1;
+	sqlite3 *pdb;
+	int timeout_idle_secs;
+	int timeout_absolute_secs;
+	int timeout_anon_absolute_secs;
+	int timeout_email_secs;
+	time_t last_session_expire;
+	struct lwsgs_user u;
+};
+
+struct per_session_data__gs {
+	struct lws_spa *spa;
+	lwsgw_hash login_session;
+	lwsgw_hash delete_session;
+	unsigned int login_expires;
+	char onward[256];
+	char result[500 + LWS_PRE];
+	char urldec[500 + LWS_PRE];
+	int result_len;
+	char ip[46];
+	struct lws_process_html_state phs;
+	int spos;
+
+	unsigned int logging_out:1;
+};
+
+/* utils.c */
+
+int
+lwsgs_lookup_callback_user(void *priv, int cols, char **col_val,
+			   char **col_name);
+void
+lwsgw_cookie_from_session(lwsgw_hash *sid, time_t expires, char **p, char *end);
+int
+lwsgs_get_sid_from_wsi(struct lws *wsi, lwsgw_hash *sid);
+int
+lwsgs_lookup_session(struct per_vhost_data__gs *vhd,
+		     const lwsgw_hash *sid, char *username, int len);
+int
+lwsgs_get_auth_level(struct per_vhost_data__gs *vhd,
+		     const char *username);
+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);
+unsigned int
+lwsgs_now_secs(void);
+int
+lwsgw_check_admin(struct per_vhost_data__gs *vhd,
+		  const char *username, const char *password);
+int
+lwsgs_hash_password(struct per_vhost_data__gs *vhd,
+		    const char *password, struct lwsgs_user *u);
+int
+lwsgs_new_session_id(struct per_vhost_data__gs *vhd,
+		     lwsgw_hash *sid, const char *username, int exp);
+int
+lwsgs_lookup_user(struct per_vhost_data__gs *vhd,
+		  const char *username, struct lwsgs_user *u);
+int
+lwsgw_update_session(struct per_vhost_data__gs *vhd,
+		     lwsgw_hash *hash, const char *user);
+int
+lwsgw_expire_old_sessions(struct per_vhost_data__gs *vhd);
+
+
+/* handlers.c */
+
+int
+lwsgs_handler_confirm(struct per_vhost_data__gs *vhd, struct lws *wsi,
+		      struct per_session_data__gs *pss);
+int
+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);
+int
+lwsgs_handler_change_password(struct per_vhost_data__gs *vhd, struct lws *wsi,
+			      struct per_session_data__gs *pss);
+int
+lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd, struct lws *wsi,
+			     struct per_session_data__gs *pss);
+int
+lwsgs_handler_register_form(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
new file mode 100644
index 00000000..6bf5d2b2
--- /dev/null
+++ b/plugins/generic-sessions/protocol_generic_sessions.c
@@ -0,0 +1,901 @@
+/*
+ * ws protocol handler plugin for "generic sessions"
+ *
+ * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation:
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ */
+
+#include "private-lwsgs.h"
+
+/* keep changes in sync with the enum in lwsgs.h */
+static const char * const param_names[] = {
+	"username",
+	"password",
+	"password2",
+	"email",
+	"register",
+	"good",
+	"bad",
+	"reg-good",
+	"reg-bad",
+	"admin",
+	"forgot",
+	"forgot-good",
+	"forgot-bad",
+	"forgot-post-good",
+	"forgot-post-bad",
+	"change",
+	"curpw",
+	"delete"
+};
+
+struct lwsgs_fill_args {
+	char *buf;
+	int len;
+};
+
+static const struct lws_protocols protocols[];
+
+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")) {
+			strncpy(a->buf, col_val[n], a->len - 1);
+			a->buf[a->len - 1] = '\0';
+			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;
+
+	snprintf(ss, sizeof(ss) - 1,
+		 "select content from email where username='%s';",
+		 lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1));
+
+	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;
+}
+
+static int
+lwsgs_email_cb_sent(struct lws_email *email)
+{
+	struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)email->data;
+	char s[200], esc[50];
+
+	/* mark the user as having sent the verification email */
+	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;
+	}
+
+	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;
+}
+
+static int
+lwsgs_email_cb_on_next(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
+	 */
+	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;
+	}
+
+	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';
+	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;
+	}
+
+	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;
+
+	strncpy(email->email_to, vhd->u.email, sizeof(email->email_to) - 1);
+
+	return 0;
+}
+
+
+struct lwsgs_subst_args
+{
+	struct per_session_data__gs *pss;
+	struct per_vhost_data__gs *vhd;
+	struct lws *wsi;
+};
+
+static const char *
+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];
+	int n;
+
+	a->pss->result[0] = '\0';
+	u.email[0] = '\0';
+	if (!lwsgs_get_sid_from_wsi(a->wsi, &sid)) {
+		if (lwsgs_lookup_session(a->vhd, &sid, a->pss->result, 31)) {
+			lwsl_notice("sid lookup for %s failed\n", sid.id);
+			a->pss->delete_session = sid;
+			return NULL;
+		}
+		snprintf(s, sizeof(s) - 1, "select username,email "
+			 "from users where username = '%s';",
+			 lws_sql_purify(esc, a->pss->result, sizeof(esc) - 1));
+		if (sqlite3_exec(a->vhd->pdb, s, lwsgs_lookup_callback_user,
+				 &u, NULL) != SQLITE_OK) {
+			lwsl_err("Unable to lookup token: %s\n",
+				 sqlite3_errmsg(a->vhd->pdb));
+			a->pss->delete_session = sid;
+			return NULL;
+		}
+	} else
+		lwsl_notice("no sid\n");
+
+	strncpy(a->pss->result + 32, u.email, 100);
+
+	switch (index) {
+	case 0:
+		return a->pss->result;
+
+	case 1:
+		n = lwsgs_get_auth_level(a->vhd, a->pss->result);
+		sprintf(a->pss->result, "%d", n);
+		return a->pss->result;
+	case 2:
+		return a->pss->result + 32;
+	}
+
+	return NULL;
+}
+
+static int
+callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
+			  void *user, void *in, size_t len)
+{
+	struct per_session_data__gs *pss = (struct per_session_data__gs *)user;
+	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]);
+	char cookie[1024], username[32], *pc = cookie;
+	unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
+	struct lws_process_html_args *args;
+	struct lws_session_info *sinfo;
+	char s[LWSGS_EMAIL_CONTENT_SIZE];
+	unsigned char *p, *start, *end;
+	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));
+		if (!vhd)
+			return 1;
+		vhd->context = lws_get_context(wsi);
+
+		/* defaults */
+		vhd->timeout_idle_secs = 600;
+		vhd->timeout_absolute_secs = 36000;
+		vhd->timeout_anon_absolute_secs = 1200;
+		vhd->timeout_email_secs = 24 * 3600;
+		strcpy(vhd->email.email_helo, "unconfigured.com");
+		strcpy(vhd->email.email_from, "noreply@unconfigured.com");
+		strcpy(vhd->email_title, "Registration Email from unconfigured");
+		strcpy(vhd->email.email_smtp_ip, "127.0.0.1");
+
+		vhd->email.on_next = lwsgs_email_cb_on_next;
+		vhd->email.on_get_body = lwsgs_email_cb_get_body;
+		vhd->email.on_sent = lwsgs_email_cb_sent;
+		vhd->email.data = (void *)vhd;
+
+		pvo = (const struct lws_protocol_vhost_options *)in;
+		while (pvo) {
+			if (!strcmp(pvo->name, "admin-user"))
+				strncpy(vhd->admin_user, pvo->value,
+					sizeof(vhd->admin_user) - 1);
+			if (!strcmp(pvo->name, "admin-password-sha1"))
+				strncpy(vhd->admin_password_sha1.id, pvo->value,
+					sizeof(vhd->admin_password_sha1.id) - 1);
+			if (!strcmp(pvo->name, "session-db"))
+				strncpy(vhd->session_db, pvo->value,
+					sizeof(vhd->session_db) - 1);
+			if (!strcmp(pvo->name, "confounder"))
+				strncpy(vhd->confounder, pvo->value,
+					sizeof(vhd->confounder) - 1);
+			if (!strcmp(pvo->name, "email-from"))
+				strncpy(vhd->email.email_from, pvo->value,
+					sizeof(vhd->email.email_from) - 1);
+			if (!strcmp(pvo->name, "email-helo"))
+				strncpy(vhd->email.email_helo, pvo->value,
+					sizeof(vhd->email.email_helo) - 1);
+			if (!strcmp(pvo->name, "email-template"))
+				strncpy(vhd->email_template, pvo->value,
+					sizeof(vhd->email_template) - 1);
+			if (!strcmp(pvo->name, "email-title"))
+				strncpy(vhd->email_title, pvo->value,
+					sizeof(vhd->email_title) - 1);
+			if (!strcmp(pvo->name, "email-contact-person"))
+				strncpy(vhd->email_contact_person, pvo->value,
+					sizeof(vhd->email_contact_person) - 1);
+			if (!strcmp(pvo->name, "email-confirm-url-base"))
+				strncpy(vhd->email_confirm_url, pvo->value,
+					sizeof(vhd->email_confirm_url) - 1);
+			if (!strcmp(pvo->name, "email-server-ip"))
+				strncpy(vhd->email.email_smtp_ip, pvo->value,
+					sizeof(vhd->email.email_smtp_ip) - 1);
+
+			if (!strcmp(pvo->name, "timeout-idle-secs"))
+				vhd->timeout_idle_secs = atoi(pvo->value);
+			if (!strcmp(pvo->name, "timeout-absolute-secs"))
+				vhd->timeout_absolute_secs = atoi(pvo->value);
+			if (!strcmp(pvo->name, "timeout-anon-absolute-secs"))
+				vhd->timeout_anon_absolute_secs = atoi(pvo->value);
+			if (!strcmp(pvo->name, "email-expire"))
+				vhd->timeout_email_secs = atoi(pvo->value);
+			pvo = pvo->next;
+		}
+		if (!vhd->admin_user[0] ||
+		    !vhd->admin_password_sha1.id[0] ||
+		    !vhd->session_db[0]) {
+			lwsl_err("generic-sessions: "
+				 "You must give \"admin-user\", "
+				 "\"admin-password-sha1\", "
+				 "and \"session_db\" per-vhost options\n");
+			return 1;
+		}
+
+		if (sqlite3_open_v2(vhd->session_db, &vhd->pdb,
+				    SQLITE_OPEN_READWRITE |
+				    SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) {
+			lwsl_err("Unable to open session db %s: %s\n",
+				 vhd->session_db, sqlite3_errmsg(vhd->pdb));
+
+			return 1;
+		}
+
+		if (sqlite3_prepare(vhd->pdb,
+				    "create table if not exists sessions ("
+				    " name char(40),"
+				    " username varchar(32),"
+				    " expire integer"
+				    ");",
+				    -1, &sm, NULL) != SQLITE_OK) {
+			lwsl_err("Unable to prepare session table init: %s\n",
+				 sqlite3_errmsg(vhd->pdb));
+
+			return 1;
+		}
+
+		if (sqlite3_step(sm) != SQLITE_DONE) {
+			lwsl_err("Unable to run session table init: %s\n",
+				 sqlite3_errmsg(vhd->pdb));
+
+			return 1;
+		}
+		sqlite3_finalize(sm);
+
+		if (sqlite3_exec(vhd->pdb,
+				 "create table if not exists users ("
+				 " username varchar(32),"
+				 " creation_time integer,"
+				 " ip varchar(46),"
+				 " email varchar(100),"
+				 " pwhash varchar(42),"
+				 " pwsalt varchar(42),"
+				 " pwchange_time integer,"
+				 " token varchar(42),"
+				 " verified integer,"
+				 " token_time integer,"
+				 " last_forgot_validated integer,"
+				 " primary key (username)"
+				 ");",
+				 NULL, NULL, NULL) != SQLITE_OK) {
+			lwsl_err("Unable to create user table: %s\n",
+				 sqlite3_errmsg(vhd->pdb));
+
+			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;
+		}
+
+		lws_email_init(&vhd->email, lws_uv_getloop(vhd->context, 0),
+				LWSGS_EMAIL_CONTENT_SIZE);
+		break;
+
+	case LWS_CALLBACK_PROTOCOL_DESTROY:
+		if (vhd->pdb) {
+			sqlite3_close(vhd->pdb);
+			vhd->pdb = NULL;
+		}
+		lws_email_destroy(&vhd->email);
+		break;
+
+	case LWS_CALLBACK_HTTP:
+		lwsl_info("LWS_CALLBACK_HTTP: %s\n", in);
+
+		pss->login_session.id[0] = '\0';
+		pss->phs.pos = 0;
+		strncpy(pss->onward, (char *)in, sizeof(pss->onward));
+
+		if (!strcmp((const char *)in, "/lwsgs-forgot")) {
+			lwsgs_handler_forgot(vhd, wsi, pss);
+			goto redirect_with_cookie;
+		}
+
+		if (!strcmp((const char *)in, "/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);
+			goto try_to_reuse;
+		}
+
+		if (!strcmp((const char *)in, "/lwsgs-login"))
+			break;
+		if (!strcmp((const char *)in, "/lwsgs-logout"))
+			break;
+		if (!strcmp((const char *)in, "/lwsgs-forgot"))
+			break;
+		if (!strcmp((const char *)in, "/lwsgs-change"))
+			break;
+
+		/* if no legitimate url for GET, return 404 */
+
+		lwsl_err("http doing 404 on %s\n", in);
+		lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
+		goto try_to_reuse;
+
+	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");
+		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);
+				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;
+				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 */
+				goto redirect_with_cookie;
+			}
+		} else
+			lwsl_notice("failed to get sid from wsi\n");
+
+		n = lwsgs_get_auth_level(vhd, username);
+
+		if ((args->max_len & n) != args->max_len) {
+			lwsl_notice("Access rights fail 0x%X vs 0x%X (cookie %s)\n",
+					args->max_len, n, sid.id);
+			return 1;
+		}
+		lwsl_debug("Access rights OK\n");
+		break;
+
+	case LWS_CALLBACK_SESSION_INFO:
+	{
+		struct lwsgs_user u;
+		sinfo = (struct lws_session_info *)in;
+		sinfo->username[0] = '\0';
+		sinfo->email[0] = '\0';
+		sinfo->ip[0] = '\0';
+		sinfo->session[0] = '\0';
+		sinfo->mask = 0;
+
+		sid.id[0] = '\0';
+		lwsl_debug("LWS_CALLBACK_SESSION_INFO\n");
+		if (lwsgs_get_sid_from_wsi(wsi, &sid))
+			break;
+		if (lwsgs_lookup_session(vhd, &sid, username, sizeof(username)))
+			break;
+
+		snprintf(s, sizeof(s) - 1,
+			 "select username, email from users where username='%s';",
+			 username);
+		if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
+		    SQLITE_OK) {
+			lwsl_err("Unable to lookup token: %s\n",
+				 sqlite3_errmsg(vhd->pdb));
+			break;
+		}
+		strncpy(sinfo->username, u.username, sizeof(sinfo->username));
+		strncpy(sinfo->email, u.email, sizeof(sinfo->email));
+		strncpy(sinfo->session, sid.id, sizeof(sinfo->session));
+		sinfo->mask = lwsgs_get_auth_level(vhd, username);
+		lws_get_peer_simple(wsi, sinfo->ip, sizeof(sinfo->ip));
+	}
+
+		break;
+
+	case LWS_CALLBACK_PROCESS_HTML:
+
+		args = (struct lws_process_html_args *)in;
+		{
+			static const char * const vars[] = {
+				"$lwsgs_user",
+				"$lwsgs_auth",
+				"$lwsgs_email"
+			};
+			struct lwsgs_subst_args a;
+
+			a.vhd = vhd;
+			a.pss = pss;
+			a.wsi = wsi;
+
+			pss->phs.vars = vars;
+			pss->phs.count_vars = ARRAY_SIZE(vars);
+			pss->phs.replace = lwsgs_subst;
+			pss->phs.data = &a;
+
+			if (lws_chunked_html_process(args, &pss->phs))
+				return -1;
+		}
+		break;
+
+	case LWS_CALLBACK_HTTP_BODY:
+		if (len < 2)
+			break;
+
+		if (!pss->spa) {
+			pss->spa = lws_spa_create(wsi, param_names,
+						ARRAY_SIZE(param_names), 1024,
+						NULL, NULL);
+			if (!pss->spa)
+				return -1;
+		}
+
+		if (lws_spa_process(pss->spa, in, len)) {
+			lwsl_notice("spa process blew\n");
+			return -1;
+		}
+		break;
+
+	case LWS_CALLBACK_HTTP_BODY_COMPLETION:
+
+		if (!pss->spa)
+			break;
+
+		lwsl_info("LWS_CALLBACK_HTTP_BODY_COMPLETION: %s\n", pss->onward);
+		lws_spa_finalize(pss->spa);
+
+		if (!strcmp((char *)pss->onward, "/lwsgs-change")) {
+			if (!lwsgs_handler_change_password(vhd, wsi, pss)) {
+				cp = lws_spa_get_string(pss->spa, FGS_GOOD);
+				goto pass;
+			}
+
+			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));
+			strncpy(pss->onward, cp, sizeof(pss->onward) - 1);
+			pss->onward[sizeof(pss->onward) - 1] = '\0';
+			goto completion_flow;
+		}
+
+		if (!strcmp((char *)pss->onward, "/lwsgs-login")) {
+			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)) {
+					n = FGS_FORGOT_BAD;
+					goto reg_done;
+				}
+				/* get the email monitor to take a look */
+				lws_email_check(&vhd->email);
+				n = FGS_FORGOT_GOOD;
+				goto reg_done;
+			}
+
+			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));
+				return -1;
+			}
+
+			if (lws_spa_get_string(pss->spa, FGS_REGISTER) &&
+			    lws_spa_get_string(pss->spa, FGS_REGISTER)[0]) {
+
+				if (lwsgs_handler_register_form(vhd, wsi, pss))
+					n = FGS_REG_BAD;
+				else {
+					n = FGS_REG_GOOD;
+
+					/* get the email monitor to take a look */
+					lws_email_check(&vhd->email);
+				}
+reg_done:
+				strncpy(pss->onward, lws_spa_get_string(pss->spa, n),
+					sizeof(pss->onward) - 1);
+				pss->onward[sizeof(pss->onward) - 1] = '\0';
+				pss->login_expires = 0;
+				pss->logging_out = 1;
+				goto completion_flow;
+			}
+
+			/* we have the username and password... check if admin */
+			if (lwsgw_check_admin(vhd, lws_spa_get_string(pss->spa, FGS_USERNAME),
+					      lws_spa_get_string(pss->spa, FGS_PASSWORD))) {
+				if (lws_spa_get_string(pss->spa, FGS_ADMIN))
+					cp = lws_spa_get_string(pss->spa, FGS_ADMIN);
+				else
+					if (lws_spa_get_string(pss->spa, FGS_GOOD))
+						cp = lws_spa_get_string(pss->spa, FGS_GOOD);
+					else {
+						lwsl_info("No admin or good target url in form\n");
+						return -1;
+					}
+				lwsl_debug("admin\n");
+				goto pass;
+			}
+
+			/* 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");
+				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));
+
+			if (!lws_spa_get_string(pss->spa, FGS_BAD)) {
+				lwsl_info("No admin or good target url in form\n");
+				return -1;
+			}
+
+			strncpy(pss->onward, lws_spa_get_string(pss->spa, FGS_BAD),
+				sizeof(pss->onward) - 1);
+			pss->onward[sizeof(pss->onward) - 1] = '\0';
+			lwsl_debug("failed\n");
+
+			goto completion_flow;
+		}
+
+		if (!strcmp((char *)pss->onward, "/lwsgs-logout")) {
+
+			lwsl_notice("/logout\n");
+
+			if (lwsgs_get_sid_from_wsi(wsi, &pss->login_session)) {
+				lwsl_notice("not logged in...\n");
+				return 1;
+			}
+
+			lwsgw_update_session(vhd, &pss->login_session, "");
+
+			if (!lws_spa_get_string(pss->spa, FGS_GOOD)) {
+				lwsl_info("No admin or good target url in form\n");
+				return -1;
+			}
+
+			strncpy(pss->onward, lws_spa_get_string(pss->spa, FGS_GOOD), sizeof(pss->onward) - 1);
+			pss->onward[sizeof(pss->onward) - 1] = '\0';
+
+			pss->login_expires = 0;
+			pss->logging_out = 1;
+
+			goto completion_flow;
+		}
+
+		break;
+
+pass:
+		strncpy(pss->onward, cp, sizeof(pss->onward) - 1);
+		pss->onward[sizeof(pss->onward) - 1] = '\0';
+
+		if (lwsgs_get_sid_from_wsi(wsi, &sid))
+			sid.id[0] = '\0';
+
+		pss->login_expires = lws_now_secs() +
+				     vhd->timeout_absolute_secs;
+
+		if (!sid.id[0]) {
+			/* 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))
+				goto try_to_reuse;
+
+			lwsl_info("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);
+			lwsgw_update_session(vhd, &sid,
+				lws_spa_get_string(pss->spa, FGS_USERNAME));
+			pss->login_session = sid;
+		}
+
+completion_flow:
+		lwsgw_expire_old_sessions(vhd);
+		goto redirect_with_cookie;
+
+	case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
+		if (pss->spa) {
+			lws_spa_destroy(pss->spa);
+			pss->spa = NULL;
+		}
+		break;
+
+	case LWS_CALLBACK_ADD_HEADERS:
+		lwsgw_expire_old_sessions(vhd);
+
+		args = (struct lws_process_html_args *)in;
+
+		if (pss->delete_session.id[0]) {
+			pc = cookie;
+			lwsgw_cookie_from_session(&pss->delete_session, 0, &pc,
+						  cookie + sizeof(cookie) - 1);
+
+			lwsl_info("deleting cookie '%s'\n", cookie);
+
+			if (lws_add_http_header_by_name(wsi,
+					(unsigned char *)"set-cookie:",
+					(unsigned char *)cookie, pc - cookie,
+					(unsigned char **)&args->p,
+					(unsigned char *)args->p + args->max_len))
+				return 1;
+		}
+
+		if (!pss->login_session.id[0])
+			lwsgs_get_sid_from_wsi(wsi, &pss->login_session);
+
+		if (!pss->login_session.id[0] && !pss->logging_out) {
+
+			pss->login_expires = lws_now_secs() +
+					     vhd->timeout_anon_absolute_secs;
+			if (lwsgs_new_session_id(vhd, &pss->login_session, "",
+						 pss->login_expires))
+				goto try_to_reuse;
+			pc = cookie;
+			lwsgw_cookie_from_session(&pss->login_session,
+						  pss->login_expires, &pc,
+						  cookie + sizeof(cookie) - 1);
+
+			lwsl_info("LWS_CALLBACK_ADD_HEADERS: setting cookie '%s'\n", cookie);
+			if (lws_add_http_header_by_name(wsi,
+					(unsigned char *)"set-cookie:",
+					(unsigned char *)cookie, pc - cookie,
+					(unsigned char **)&args->p,
+					(unsigned char *)args->p + args->max_len))
+				return 1;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+
+redirect_with_cookie:
+	p = buffer + LWS_PRE;
+	start = p;
+	end = p + sizeof(buffer) - LWS_PRE;
+
+	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;
+
+	if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
+			(unsigned char *)"text/html", 9, &p, end))
+		return 1;
+	if (lws_add_http_header_content_length(wsi, 0, &p, end))
+		return 1;
+
+	if (pss->delete_session.id[0]) {
+		lwsgw_cookie_from_session(&pss->delete_session, 0, &pc,
+					  cookie + sizeof(cookie) - 1);
+
+		lwsl_notice("deleting cookie '%s'\n", cookie);
+
+		if (lws_add_http_header_by_name(wsi,
+				(unsigned char *)"set-cookie:",
+				(unsigned char *)cookie, pc - cookie,
+				&p, end))
+			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))
+			return 1;
+	} else
+		pss->login_expires = lws_now_secs() +
+				     vhd->timeout_absolute_secs;
+
+	if (pss->login_session.id[0] || pss->logging_out) {
+		/*
+		 * we succeeded to login, we must issue a login
+		 * cookie with the prepared data
+		 */
+		pc = cookie;
+
+		lwsgw_cookie_from_session(&pss->login_session,
+					  pss->login_expires, &pc,
+					  cookie + sizeof(cookie) - 1);
+
+		lwsl_info("setting cookie '%s'\n", cookie);
+
+		pss->logging_out = 0;
+
+		if (lws_add_http_header_by_name(wsi,
+				(unsigned char *)"set-cookie:",
+				(unsigned char *)cookie, pc - cookie,
+				&p, end))
+			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 < 0)
+		return 1;
+
+	/* fallthru */
+
+try_to_reuse:
+	if (lws_http_transaction_completed(wsi))
+		return -1;
+
+	return 0;
+}
+
+static const struct lws_protocols protocols[] = {
+	{
+		"protocol-generic-sessions",
+		callback_generic_sessions,
+		sizeof(struct per_session_data__gs),
+		1024,
+	},
+};
+
+LWS_EXTERN LWS_VISIBLE int
+init_protocol_generic_sessions(struct lws_context *context,
+			struct lws_plugin_capability *c)
+{
+	if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
+		lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
+			 c->api_magic);
+		return 1;
+	}
+
+	c->protocols = protocols;
+	c->count_protocols = ARRAY_SIZE(protocols);
+	c->extensions = NULL;
+	c->count_extensions = 0;
+
+	return 0;
+}
+
+LWS_EXTERN LWS_VISIBLE int
+destroy_protocol_generic_sessions(struct lws_context *context)
+{
+	return 0;
+}
diff --git a/plugins/generic-sessions/utils.c b/plugins/generic-sessions/utils.c
new file mode 100644
index 00000000..0d458d7b
--- /dev/null
+++ b/plugins/generic-sessions/utils.c
@@ -0,0 +1,450 @@
+/*
+ * ws protocol handler plugin for "generic sessions"
+ *
+ * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation:
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ */
+
+#include "private-lwsgs.h"
+
+void
+sha1_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++) {
+		*p++ = hex[hash[n] >> 4];
+		*p++ = hex[hash[n] & 15];
+	}
+
+	*p = '\0';
+}
+
+int
+lwsgw_check_admin(struct per_vhost_data__gs *vhd,
+		  const char *username, const char *password)
+{
+	lwsgw_hash_bin hash_bin;
+	lwsgw_hash pw_hash;
+
+	if (strcmp(vhd->admin_user, username))
+		return 0;
+
+	lws_SHA1((unsigned char *)password, strlen(password), hash_bin.bin);
+	sha1_to_lwsgw_hash(hash_bin.bin, &pw_hash);
+
+	return !strcmp(vhd->admin_password_sha1.id, pw_hash.id);
+}
+
+/*
+ * secure cookie: it can only be passed over https where it cannot be
+ *		  snooped in transit
+ * HttpOnly:	  it can only be accessed via http[s] transport, it cannot be
+ *		  gotten at by JS
+ */
+void
+lwsgw_cookie_from_session(lwsgw_hash *sid, time_t expires, char **p, char *end)
+{
+	struct tm *tm = gmtime(&expires);
+	time_t n = lws_now_secs();
+
+	*p += snprintf(*p, end - *p, "id=%s;Expires=", sid->id);
+#ifdef WIN32
+	*p += strftime(*p, end - *p, "%Y %H:%M %Z", tm);
+#else
+	*p += strftime(*p, end - *p, "%F %H:%M %Z", tm);
+#endif
+	*p += snprintf(*p, end - *p, ";path=/");
+	*p += snprintf(*p, end - *p, ";Max-Age=%lu", (unsigned long)(expires - n));
+//	*p += snprintf(*p, end - *p, ";secure");
+	*p += snprintf(*p, end - *p, ";HttpOnly");
+}
+
+int
+lwsgw_expire_old_sessions(struct per_vhost_data__gs *vhd)
+{
+	time_t n = lws_now_secs();
+	char s[200];
+
+	if (n - vhd->last_session_expire < 5)
+		return 0;
+
+	vhd->last_session_expire = n;
+
+	snprintf(s, sizeof(s) - 1,
+		 "delete from sessions where "
+		 "expire <= %lu;", (unsigned long)n);
+
+	if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
+		lwsl_err("Unable to expire sessions: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+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];
+
+	if (user[0])
+		n += vhd->timeout_absolute_secs;
+	else
+		n += vhd->timeout_anon_absolute_secs;
+
+	snprintf(s, sizeof(s) - 1,
+		 "update sessions set expire=%lu,username='%s' where name='%s';",
+		 (unsigned long)n,
+		 lws_sql_purify(esc, user, sizeof(esc)),
+		 lws_sql_purify(esc1, hash->id, sizeof(esc1)));
+
+	if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
+		lwsl_err("Unable to update session: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+lwsgw_session_from_cookie(const char *cookie, lwsgw_hash *sid)
+{
+	const char *p = cookie;
+	int n;
+
+	while (*p) {
+		if (p[0] == 'i' && p[1] == 'd' && p[2] == '=') {
+			p += 3;
+			break;
+		}
+		p++;
+	}
+	if (!*p) {
+		lwsl_info("no id= in cookie\n");
+		return 1;
+	}
+
+	for (n = 0; n < sizeof(sid->id) - 1 && *p; n++) {
+		/* our SID we issue only has these chars */
+		if ((*p >= '0' && *p <= '9') ||
+		    (*p >= 'a' && *p <= 'f'))
+			sid->id[n] = *p++;
+		else {
+			lwsl_info("bad chars in cookie id %c\n", *p);
+			return 1;
+		}
+	}
+
+	if (n < sizeof(sid->id) - 1) {
+		lwsl_info("cookie id too short\n");
+		return 1;
+	}
+
+	sid->id[sizeof(sid->id) - 1] = '\0';
+
+	return 0;
+}
+
+int
+lwsgs_get_sid_from_wsi(struct lws *wsi, lwsgw_hash *sid)
+{
+	char cookie[1024];
+
+	/* fail it on no cookie */
+	if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
+		lwsl_info("%s: no cookie\n", __func__);
+		return 1;
+	}
+	if (lws_hdr_copy(wsi, cookie, sizeof cookie, WSI_TOKEN_HTTP_COOKIE) < 0) {
+		lwsl_info("cookie copy failed\n");
+		return 1;
+	}
+	/* extract the sid from the cookie */
+	if (lwsgw_session_from_cookie(cookie, sid)) {
+		lwsl_info("session from cookie failed\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+struct lla {
+	char *username;
+	int len;
+	int results;
+};
+
+static int
+lwsgs_lookup_callback(void *priv, int cols, char **col_val, char **col_name)
+{
+	struct lla *lla = (struct lla *)priv;
+
+	//lwsl_err("%s: %d\n", __func__, cols);
+
+	if (cols)
+		lla->results = 0;
+	if (col_val && col_val[0]) {
+		strncpy(lla->username, col_val[0], lla->len);
+		lla->username[lla->len - 1] = '\0';
+		lwsl_info("%s: %s\n", __func__, lla->username);
+	}
+
+	return 0;
+}
+
+int
+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];
+
+	lwsgw_expire_old_sessions(vhd);
+
+	snprintf(s, sizeof(s) - 1,
+		 "select username from sessions where name = '%s';",
+		 lws_sql_purify(esc, sid->id, sizeof(esc) - 1));
+
+	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback, &lla, NULL) != SQLITE_OK) {
+		lwsl_err("Unable to create user table: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+
+		return 1;
+	}
+
+	/* 0 if found */
+	return lla.results;
+}
+
+int
+lwsgs_lookup_callback_user(void *priv, int cols, char **col_val, char **col_name)
+{
+	struct lwsgs_user *u = (struct lwsgs_user *)priv;
+	int n;
+
+	for (n = 0; n < cols; n++) {
+		if (!strcmp(col_name[n], "username")) {
+			strncpy(u->username, col_val[n], sizeof(u->username) - 1);
+			u->username[sizeof(u->username) - 1] = '\0';
+			continue;
+		}
+		if (!strcmp(col_name[n], "ip")) {
+			strncpy(u->ip, col_val[n], sizeof(u->ip) - 1);
+			u->ip[sizeof(u->ip) - 1] = '\0';
+			continue;
+		}
+		if (!strcmp(col_name[n], "creation_time")) {
+			u->created = atol(col_val[n]);
+			continue;
+		}
+		if (!strcmp(col_name[n], "last_forgot_validated")) {
+			if (col_val[n])
+				u->last_forgot_validated = atol(col_val[n]);
+			else
+				u->last_forgot_validated = 0;
+			continue;
+		}
+		if (!strcmp(col_name[n], "email")) {
+			strncpy(u->email, col_val[n], sizeof(u->email) - 1);
+			u->email[sizeof(u->email) - 1] = '\0';
+			continue;
+		}
+		if (!strcmp(col_name[n], "verified")) {
+			u->verified = atoi(col_val[n]);
+			continue;
+		}
+		if (!strcmp(col_name[n], "pwhash")) {
+			strncpy(u->pwhash.id, col_val[n], sizeof(u->pwhash.id) - 1);
+			u->pwhash.id[sizeof(u->pwhash.id) - 1] = '\0';
+			continue;
+		}
+		if (!strcmp(col_name[n], "pwsalt")) {
+			strncpy(u->pwsalt.id, col_val[n], sizeof(u->pwsalt.id) - 1);
+			u->pwsalt.id[sizeof(u->pwsalt.id) - 1] = '\0';
+			continue;
+		}
+		if (!strcmp(col_name[n], "token")) {
+			strncpy(u->token.id, col_val[n], sizeof(u->token.id) - 1);
+			u->token.id[sizeof(u->token.id) - 1] = '\0';
+			continue;
+		}
+	}
+	return 0;
+}
+
+int
+lwsgs_lookup_user(struct per_vhost_data__gs *vhd,
+		  const char *username, struct lwsgs_user *u)
+{
+	char s[150], esc[50];
+
+	u->username[0] = '\0';
+	snprintf(s, sizeof(s) - 1,
+		 "select username,creation_time,ip,email,verified,pwhash,pwsalt,last_forgot_validated "
+		 "from users where username = '%s';",
+		 lws_sql_purify(esc, username, sizeof(esc) - 1));
+
+	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, u, NULL) !=
+	    SQLITE_OK) {
+		lwsl_err("Unable to lookup user: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+
+		return -1;
+	}
+
+	return !u->username[0];
+}
+
+int
+lwsgs_new_session_id(struct per_vhost_data__gs *vhd,
+		     lwsgw_hash *sid, const char *username, int exp)
+{
+	unsigned char sid_rand[20];
+	const char *u;
+	char s[300], esc[50], esc1[50];
+
+	if (username)
+		u = username;
+	else
+		u = "";
+
+	if (!sid)
+		return 1;
+
+	memset(sid, 0, sizeof(*sid));
+
+	if (lws_get_random(vhd->context, sid_rand, sizeof(sid_rand)) !=
+			   sizeof(sid_rand))
+		return 1;
+
+	sha1_to_lwsgw_hash(sid_rand, sid);
+
+	snprintf(s, sizeof(s) - 1,
+		 "insert into sessions(name, username, expire) "
+		 "values ('%s', '%s', %u);",
+		 lws_sql_purify(esc, sid->id, sizeof(esc) - 1),
+		 lws_sql_purify(esc1, u, sizeof(esc1) - 1), exp);
+
+	if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
+		lwsl_err("Unable to insert session: %s\n",
+			 sqlite3_errmsg(vhd->pdb));
+
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+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 */
+	}
+
+	if (!lwsgs_lookup_user(vhd, username, &u)) {
+		if ((u.verified & 0xff) == LWSGS_VERIFIED_ACCEPTED)
+			n |= LWSGS_AUTH_VERIFIED;
+
+		if (u.last_forgot_validated > lws_now_secs() - 300)
+			n |= LWSGS_AUTH_FORGOT_FLOW;
+	}
+
+	return n;
+}
+
+int
+lwsgs_check_credentials(struct per_vhost_data__gs *vhd,
+			const char *username, const char *password)
+{
+	unsigned char buffer[300];
+	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 = snprintf((char *)buffer, sizeof(buffer) - 1,
+		     "%s-%s-%s", password, vhd->confounder, u.pwsalt.id);
+
+	/* sha1sum of password + salt */
+	lws_SHA1(buffer, n, hash_bin.bin);
+	sha1_to_lwsgw_hash(&hash_bin.bin[0], &hash);
+
+	return !!strcmp(hash.id, u.pwhash.id);
+}
+
+/* sets u->pwsalt and u->pwhash */
+
+int
+lwsgs_hash_password(struct per_vhost_data__gs *vhd,
+		    const char *password, struct lwsgs_user *u)
+{
+	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 */
+
+	if (lws_get_random(vhd->context, sid_rand,
+			   sizeof(sid_rand)) !=
+			   sizeof(sid_rand)) {
+		lwsl_err("Problem getting random for salt\n");
+		return 1;
+	}
+	sha1_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);
+
+	/* [password in ascii][salt] */
+	n = snprintf((char *)buffer, sizeof(buffer) - 1,
+		    "%s-%s-%s", password, vhd->confounder, u->pwsalt.id);
+
+	/* sha1sum of password + salt */
+	lws_SHA1(buffer, n, hash_bin.bin);
+	sha1_to_lwsgw_hash(&hash_bin.bin[0], &u->pwhash);
+
+	return 0;
+}
diff --git a/plugins/protocol_lws_status.c b/plugins/protocol_lws_status.c
index 817fe76d..912eec85 100644
--- a/plugins/protocol_lws_status.c
+++ b/plugins/protocol_lws_status.c
@@ -25,6 +25,7 @@
 #include <time.h>
 #include <string.h>
 #ifdef WIN32
+#include <io.h>
 #include <gettimeofday.h>
 #endif
 
diff --git a/plugins/protocol_post_demo.c b/plugins/protocol_post_demo.c
index 9f0cab89..8520a315 100644
--- a/plugins/protocol_post_demo.c
+++ b/plugins/protocol_post_demo.c
@@ -23,6 +23,13 @@
 #include "../lib/libwebsockets.h"
 
 #include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef WIN32
+#include <io.h>
+#endif
+#include <stdio.h>
 
 struct per_session_data__post_demo {
 	struct lws_spa *spa;
@@ -31,7 +38,7 @@ struct per_session_data__post_demo {
 
 	char filename[256];
 	long file_length;
-	int fd;
+	lws_filefd_type fd;
 };
 
 static const char * const param_names[] = {
diff --git a/test-server/test-server-v2.0.c b/test-server/test-server-v2.0.c
index b6feafe7..d12c0b6b 100644
--- a/test-server/test-server-v2.0.c
+++ b/test-server/test-server-v2.0.c
@@ -82,6 +82,9 @@ static const struct lws_http_mount mount_post = {
 	NULL,	/* default filename if none given */
 	NULL,
 	NULL,
+	NULL,
+	NULL,
+	0,
 	0,
 	0,
 	0,
@@ -104,6 +107,9 @@ static const struct lws_http_mount mount = {
 	"test.html",	/* default filename if none given */
 	NULL,
 	NULL,
+	NULL,
+	NULL,
+	0,
 	0,
 	0,
 	0,
diff --git a/test-server/test-server.h b/test-server/test-server.h
index 95474029..7158abc6 100644
--- a/test-server/test-server.h
+++ b/test-server/test-server.h
@@ -85,7 +85,7 @@ struct per_session_data__http {
 
 	char filename[256];
 	long file_length;
-	int post_fd;
+	lws_filefd_type post_fd;
 };
 
 /*
-- 
GitLab