1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

remove: generic sessions

As far as I know there are no users of this, although it worked
it's basically unmaintainable due to handling the sql and JSON
manually.

Gradually better capabilities have appeared in lws, like
lws_struct abstracting out the sql and JSON, and now generic
JWT... these have been used in Sai to great effect and displaced
the only organic would-be user of this.

There is a better path to do this stuff now and no point keeping
this around.
This commit is contained in:
Andy Green 2020-07-13 13:24:38 +01:00
parent f1f34a7d4b
commit 52a8c87838
28 changed files with 0 additions and 4257 deletions

View file

@ -134,7 +134,6 @@ if (NOT LWS_WITH_NETWORK)
set(LWS_WITH_CGI 0)
set(LWS_ROLE_RAW_PROXY 0)
set(LWS_WITH_PEER_LIMITS 0)
set(LWS_WITH_GENERIC_SESSIONS 0)
set(LWS_WITH_HTTP_STREAM_COMPRESSION 0)
set(LWS_WITH_HTTP_BROTLI 0)
set(LWS_WITH_POLL 0)
@ -228,12 +227,6 @@ if (LWS_WITH_PLUGINS OR LWS_WITH_CGI)
set(LWS_WITH_GENCRYPTO 1)
endif()
if (LWS_WITH_GENERIC_SESSIONS)
set(LWS_WITH_SQLITE3 1)
# set(LWS_WITH_SMTP 1)
set(LWS_WITH_STRUCT_SQLITE3 1)
endif()
if (LWS_PLAT_FREERTOS)
set(LWS_WITH_SHARED OFF)
set(LWS_WITH_MBEDTLS ON)

View file

@ -96,7 +96,6 @@ option(LWS_WITH_PLUGINS "Support plugins for protocols and extensions" OFF)
option(LWS_WITH_HTTP_PROXY "Support for active HTTP proxying" OFF)
option(LWS_WITH_ZIP_FOPS "Support serving pre-zipped files" OFF)
option(LWS_WITH_SOCKS5 "Allow use of SOCKS5 proxy on client connections" OFF)
option(LWS_WITH_GENERIC_SESSIONS "With the Generic Sessions plugin" OFF)
option(LWS_WITH_PEER_LIMITS "Track peers and restrict resources a single peer can allocate" OFF)
option(LWS_WITH_ACCESS_LOG "Support generating Apache-compatible access logs" OFF)
option(LWS_WITH_RANGES "Support http ranges (RFC7233)" OFF)

View file

@ -90,8 +90,6 @@ if (LWS_ROLE_WS)
"protocol_lws_mirror.c" "" "")
create_plugin(protocol_lws_status ""
"protocol_lws_status.c" "" "")
create_plugin(protocol_lws_table_dirlisting ""
"generic-table/protocol_table_dirlisting.c" "" "")
if (NOT WIN32)
create_plugin(protocol_lws_raw_test ""
"protocol_lws_raw_test.c" "" "")
@ -143,29 +141,6 @@ if (LWS_WITH_ACME)
"acme-client/protocol_lws_acme_client.c" "" "")
endif()
if (LWS_WITH_GENERIC_SESSIONS AND LWS_ROLE_WS AND LWS_WITH_TLS)
create_plugin(protocol_generic_sessions ""
"generic-sessions/protocol_generic_sessions.c"
"generic-sessions/utils.c"
"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)
create_plugin(protocol_lws_messageboard ""
"generic-sessions/protocol_lws_messageboard.c" "" "")
if (WIN32)
target_link_libraries(protocol_lws_messageboard ${LWS_SQLITE3_LIBRARIES})
else()
target_link_libraries(protocol_lws_messageboard sqlite3 )
endif(WIN32)
endif(LWS_WITH_GENERIC_SESSIONS AND LWS_ROLE_WS AND LWS_WITH_TLS)
endif(LWS_WITH_PLUGINS AND LWS_WITH_SHARED)
@ -189,36 +164,4 @@ if (LWS_WITH_SERVER_STATUS)
DESTINATION share/libwebsockets-test-server/server-status
COMPONENT examples)
endif()
if (LWS_WITH_GENERIC_SESSIONS)
install(FILES
generic-sessions/assets/lwsgs-logo.png
generic-sessions/assets/seats.jpg
generic-sessions/assets/failed-login.html
generic-sessions/assets/lwsgs.js
generic-sessions/assets/lwsgs.css
generic-sessions/assets/post-register-fail.html
generic-sessions/assets/post-register-ok.html
generic-sessions/assets/post-verify-ok.html
generic-sessions/assets/post-verify-fail.html
generic-sessions/assets/sent-forgot-ok.html
generic-sessions/assets/sent-forgot-fail.html
generic-sessions/assets/post-forgot-ok.html
generic-sessions/assets/post-forgot-fail.html
generic-sessions/assets/index.html
DESTINATION share/libwebsockets-test-server/generic-sessions
COMPONENT examples)
install(FILES generic-sessions/assets/successful-login.html
DESTINATION share/libwebsockets-test-server/generic-sessions/needauth
COMPONENT examples)
install(FILES generic-sessions/assets/admin-login.html
DESTINATION share/libwebsockets-test-server/generic-sessions/needadmin
COMPONENT examples)
endif()
install(FILES
generic-table/assets/lwsgt.js
generic-table/assets/index.html
DESTINATION share/libwebsockets-test-server/generic-table
COMPONENT examples)
endif()

View file

@ -1,5 +0,0 @@
<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>

View file

@ -1,3 +0,0 @@
<html>
This is an example destination that will appear after a failed login
</html>

View file

@ -1,56 +0,0 @@
<html>
<head>
<meta charset="UTF-8">
<script src="/lws-common.js"></script>
<link rel="stylesheet" type="text/css" href="lwsgs.css"/>
<script src="lwsgs.js"></script>
</head>
<body class="seats">
<table class="lwsgs">
<tr>
<td class="logo">
<img src="lwsgs-logo.png">
</td>
<td class="">
<div id=lwsgs class="lwsgs"></div>
</td>
</tr>
<tr><td colspan=2 class="h99">
<table class="c100"><tr>
<td class="c">
<span id="nolog" class="group2">
This is a demo application for lws generic-sessions.<br><br>
It's a simple messageboard.<br><br>
What's interesting about it is there is <b>no serverside scripting</b>,<br>
instead client js makes a wss:// connection back to the server<br>
and then reacts to JSON from the ws protocol. Sessions stuff is <br>
handled by lws generic sessions, making the <a href="https://libwebsockets.org/git/libwebsockets/tree/plugins/generic-sessions/protocol_generic_sessions.c">actual<br>
test application</a> <a href="https://libwebsockets.org/git/libwebsockets/tree/plugins/generic-sessions/protocol_lws_messageboard.c">very small</a>.<br><br>
And because it's natively websocket, it's naturally connected<br>
for dynamic events and easy to maintain.
<br><br>
Register / Login at the top right to see and create new messages.
</span>
<span id="logged" class="group2">
<div id="newmsg">
<form action="msg" method="post" target="hidden">
New message<br>
<textarea id="msg" placeholder="type your message here" cols="40" rows="5" name="msg">
</textarea><br>
<input type="submit" id="send" name="send" disabled=1>
</form>
</div>
</span>
<div id="dmessages">
<span id="messages" ></span>
</div>
<span id="debug" class="group2"></span>
</td></tr></table>
</td></tr>
</table>
</form>
<iframe name="hidden" class="hidden"></iframe>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

View file

@ -1,134 +0,0 @@
.body { font-size: 12px }
.gstitle { font-size: 18px }
.group1 {
vertical-align:middle;
text-align:center;
background:#f0f0e0;
padding:12px;
border-radius:10px;
}
.group2 {
display:none;
vertical-align:middle;
font-size: 22px;
text-align:center;
margin:auto;
align:center;
background-color: rgba(255, 255, 255, 0.8);
padding:12px;
border-radius:10px;
}
body.seats {
background-image:url(seats.jpg)
}
div.lwsgs {
z-index: 3;
text-align:right;
background-color: rgba(255, 255, 255, 0.8);
}
table.lwsgs {
width:100%;
height:100%;
transition: max-height 2s;
}
table.c100 {
text-align:center;
width:100%;
}
table.r {
vertical-align:top;
text-align:right;
}
table.l {
vertical-align:top;
text-align:left;
}
table.fixed {
table-layout: fixed;
}
td.logo {
vertical-align:top;
text-align:left;
width:200px
}
td.lwsgs {
vertical-align:top;
float:right;
}
td.h99 {
height:99%;
vertical-align:middle;
}
td.c {
margin:auto;
align:center
}
td.tac {
text-align:center
}
td.ava {
display:inline-block;
vertical-align:top;
word-wrap:break-word;
}
iframe.hidden {
display:none;
}
div.hidden {
display:none;
}
div.hiddenr {
display:none;
text-align:right;
}
input {
margin: 2px;
padding: 2px;
}
input.em {
margin: 4px;
font-weight:bold;
}
input.wide {
margin: 6px;
padding: 6px;
}
input.hidden {
display: none;
}
form.r {
text-align:right;
}
span.bad {
color: red;
}
span.small {
font-size:8pt;
}
.green {
color: green;
}

View file

@ -1,627 +0,0 @@
<!-- 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" class="hidden"> \
<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 class="r">\
<tr>\
<td>User Name\
<input type="text" size="10" id="username" name="username"></td>\
<td>Password\
<input type="password" id="password" size="10" name="password"><div id="pw1"></div></td>\
</tr><tr>\
<td colspan="2" class="c"><input type="submit" id="login" name="login" value="Login" class="em">\
&nbsp;<input type="submit" id="forgot" name="forgot" value="Forgot password">\
&nbsp;<input id="doreg" type="button" value="Sign up"></td>\
</tr>\
</table>\
</form>\
</div>\
\
<div id="dlogout" class="hiddenr">\
<form action="lwsgs-logout" method="post" class="r">\
<input type="hidden" name="good" value="index.html">\
<table class="r">\
<tr><td><span id=grav></span></td>\
<td class="tac"><table><tr><td class="tac">\
<a href="#" id="clink">\
<span id="curuser"></span></a></td></tr><tr>\
<td class="tac"><input type="submit" name="logout" value="Logout"></td>\
</tr></table></td></tr>\
</table>\
</form></div>\
\
<div id="dregister" class="hidden">\
<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 class="l">\
<tr>\
<td colspan=2 align=center>\
<span id="curuser"></span>\
<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" &nbsp;<span id=uchk></span></td>\
</tr>\
<tr>\
<td align=right>Password:</td>\
<td><input type="password" size="10" id="rpassword" name="password">&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">&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" &nbsp;<span id=echk></span></td>\
</tr>\
<tr>\
<td colspan=2 align=center>\
<input type="submit" id="register" name="register" value="Register" >\
<input type="submit" id="rforgot" name="forgot" value="Forgot Password" class="hidden">\
<input type="button" id="cancel" name="cancel" value="Cancel">\
</td>\
</tr>\
</table>\
</form>\
</div>\
\
<div id="dchange" class="hidden">\
<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 class="l">\
<tr>\
<td colspan=2 align=center>\
<span id="ccuruser"></span>\
<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"\
>&nbsp;<span id=cuchk></span></td>\
</tr>\
<tr>\
<td align=right>Password:</td>\
<td><input type="password" size="10" id="cpassword" name="password"\
&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"\
>&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="?" \
&nbsp;<span id=cechk></span></td>\
</tr> -->\
<tr>\
<td colspan=2 align=center>\
<input type="submit" id="change" name="change"\
value="Change" class="wide">\
<input type="submit" id="cforgot" name="forgot"\
value="Forgot Password" class="wide hidden">\
<input type="button" id="cancel2" name="cancel"\
value="Cancel" class="wide">\
</td>\
</tr>\
<tr>\
<td colspan=2>\
<input type="checkbox" id="showdel" name="showdel"\
> Show Delete&nbsp;\
<input type="submit" id="delete" name="delete" \
value="Delete Account" class="wide hidden">\
</td>\
</tr>\
</table>\
</form>\
</div>\
\
<div id="dadmin" class="hidden">\
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";
}
event.preventDefault()
}
var lwsgs_user_check = '0';
var lwsgs_email_check = '0';
function lwsgs_rupdate()
{
var en_register = 1, en_forgot = 0, op;
if (document.getElementById('rpassword').value ==
document.getElementById('password2').value) {
if (document.getElementById('rpassword').value.length)
document.getElementById('match').innerHTML =
"<b class=\"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 class=\"bad\">\u2718 <b>Passwords do not match</b></span>";
} else
document.getElementById('match').innerHTML =
"<span class=\"bad\">\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 class=\"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') {
var uc = document.getElementById('uchk');
if (uc) {
if (document.getElementById('rusername').value)
uc.innerHTML = "<b class=\"green\">\u2713</b>";
else
uc.innerHTML = "";
}
} else {
if (document.getElementById('uchk'))
ocument.getElementById('uchk').innerHTML = "<b class=\"red\">\u2718 Already registered</b>";
en_forgot = 1;
}
if (lwsgs_email_check === '0') {
var ec = document.getElementById('echk');
if (ec) {
if (document.getElementById('email').value)
ec.innerHTML = "<b class=\"green\">\u2713</b>";
else
ec.innerHTML = "";
}
} else {
if (document.getElementById('echk'))
document.getElementById('echk').innerHTML = "<b class=\"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, op;
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 class=\"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 class=\"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 class=\"red\">\u2718 <b>Passwords do not match</b></span>";
} else
document.getElementById('cmatch').innerHTML = "<span class=\"red\">\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 {
var cpw = document.getElementById('cpw1');
if (cpw) {
if (document.getElementById('cpassword').value.length)
cpw.innerHTML = "<b class=\"green\">\u2713</b>";
else
cpw.innerHTML = "";
}
}
if (!document.getElementById('cpassword').value ||
!document.getElementById('cpassword2').value ||
pwok === 0)
en_change = 0;
if (document.getElementById('showdel').checked)
document.getElementById('delete').style.display = "inline";
else
document.getElementById('delete').style.display = "none";
document.getElementById('change').disabled = !en_change;
document.getElementById('cpassword').disabled = pwok === 0;
document.getElementById('cpassword2').disabled = pwok === 0;
document.getElementById('showdel').disabled = pwok === 0;
document.getElementById('delete').disabled = pwok === 0;
//document.getElementById('cemail').disabled = pwok === 0;
/*
if (lwsgs_auth & 8) {
document.getElementById('cemail').style.display = "none";
document.getElementById('cemail_name').style.display = "none";
} else {
document.getElementById('cemail').style.display = "inline";
document.getElementById('cemail_name').style.display = "inline";
if (lwsgs_email_check === '0' &&
document.getElementById('cemail').value != lwsgs_email) {
if (document.getElementById('cemail').value)
document.getElementById('cechk').innerHTML = "<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 rupdate_user()
{
lwsgs_rupdate();
lwsgs_check_user();
}
function rupdate_email()
{
lwsgs_rupdate();
lwsgs_check_email('email');
}
function cupdate_email()
{
lwsgs_cupdate();
lwsgs_check_email('cemail');
}
function lwsgs_initial()
{
document.getElementById('lwsgs').innerHTML = lwsgs_html;
if (lwsgs_user) {
document.getElementById("curuser").innerHTML =
"currently logged in as " + lwsgs_san(lwsgs_user) + "</br>";
document.getElementById("ccuruser").innerHTML =
"<span class=\"gstitle\">Login settings for " +
lwsgs_san(lwsgs_user) + "</span></br>";
}
document.getElementById('username').oninput = lwsgs_update;
document.getElementById('username').onchange = lwsgs_update;
document.getElementById('password').oninput = lwsgs_update;
document.getElementById('password').onchange = lwsgs_update;
document.getElementById('doreg').onclick = lwsgs_open_registration;
document.getElementById('clink').onclick = lwsgs_select_change;
document.getElementById('cancel').onclick =lwsgs_cancel_registration;
document.getElementById('cancel2').onclick =lwsgs_cancel_registration;
document.getElementById('rpassword').oninput = lwsgs_rupdate;
document.getElementById('password2').oninput = lwsgs_rupdate;
document.getElementById('rusername').oninput = rupdate_user;
document.getElementById('email').oninput = rupdate_email;
document.getElementById('ccurpw').oninput = lwsgs_cupdate;
document.getElementById('cpassword').oninput = lwsgs_cupdate;
document.getElementById('cpassword2').oninput = lwsgs_cupdate;
<!-- document.getElementById('cemail').oninput = cupdate_email;-->
document.getElementById('showdel').onchange = lwsgs_cupdate;
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();
}
window.addEventListener("load", function() {
lwsgs_initial();
document.getElementById("nolog").style.display = !!lwsgs_user ? "none" : "inline-block";
document.getElementById("logged").style.display = !lwsgs_user ? "none" : "inline-block";
document.getElementById("msg").onkeyup = mupd;
document.getElementById("msg").onchange = mupd;
var ws;
function mb_format(s)
{
var r = "", n, wos = 0;
for (n = 0; n < s.length; n++) {
if (s[n] == ' ')
wos = 0;
else {
wos++;
if (wos === 40) {
wos = 0;
r = r + ' ';
}
}
if (s[n] == '<') {
r = r + "&lt;";
continue;
}
if (s[n] == '\n') {
r = r + "<br>";
continue;
}
r = r + s[n];
}
return r;
}
function add_div(n, m)
{
var q = document.getElementById(n);
var d = new Date(m.time * 1000);
q.innerHTML = "<br><div class=\"group2\"><table class=\"fixed\"><tr><td>" +
"<img src=\"https://www.gravatar.com/avatar/" + md5(m.email) +
"?d=identicon\"><br>" +
"<b>" + lwsgs_san(m.username) + "</b><br>" +
"<span class=\"small\">" + d.toDateString() +
"<br>" + d.toTimeString() + "</span><br>" +
"IP: " + lwsgs_san(m.ip) +
"</td><td class=\"ava\"><span>" +
mb_format(m.content) +
"</span></td></tr></table></div><br>" + q.innerHTML;
}
function get_appropriate_ws_url()
{
var pcol;
var u = document.URL;
if (u.substring(0, 5) == "https") {
pcol = "wss://";
u = u.substr(8);
} else {
pcol = "ws://";
if (u.substring(0, 4) == "http")
u = u.substr(7);
}
u = u.split('/');
return pcol + u[0] + "/xxx";
}
if (lwsgs_user) {
ws = new WebSocket(get_appropriate_ws_url(),
"protocol-lws-messageboard");
try {
ws.onopen = function() {
document.getElementById("debug").textContent = "ws opened";
}
ws.onmessage =function got_packet(msg) {
add_div("messages", JSON.parse(msg.data));
}
ws.onclose = function(){
}
} catch(exception) {
alert('<p>Error' + exception);
}
}
function mupd()
{
document.getElementById("send").disabled = !document.getElementById("msg").value;
}
}, false);

View file

@ -1,2 +0,0 @@
!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

View file

@ -1,5 +0,0 @@
<html>
Sorry, something went wrong.
Click <a href="../">here</a> to continue.
</html>

View file

@ -1,6 +0,0 @@
<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>

View file

@ -1 +0,0 @@
Registration failed, sorry

View file

@ -1,27 +0,0 @@
<html>
<head>
<script src="lwsgs.js" nonce=lwscaro></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 nonce=lwscaro>
document.getElementById('u').innerHTML = "<b>" + lwsgs_san(lwsgs_user) + "</b>";
</script>
</html>

View file

@ -1,20 +0,0 @@
<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>

View file

@ -1,25 +0,0 @@
<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 nonce="lwscaro">
document.getElementById('u').innerHTML = "<b>" + san(lwsgs_user) + "</b>";
</script>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

View file

@ -1,5 +0,0 @@
<html>
Sorry, something went wrong.
Click <a href="../">here</a> to continue.
</html>

View file

@ -1,4 +0,0 @@
An email has been sent to your registered address.
Please follow the instructions to reset your password.

View file

@ -1,4 +0,0 @@
<html>
This is an example destination that will appear after successful non-Admin login
</html>

View file

@ -1,663 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "private-lwsgs.h"
#if defined(LWS_WITH_SMTP)
static int
lwsgs_smtp_client_done(struct lws_smtp_email *e, void *buf, size_t len)
{
free(e);
return 0;
}
static int
lwsgs_smtp_client_done_sentvfy(struct lws_smtp_email *e, void *buf, size_t len)
{
struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)e->data;
const char *username = (const char *)e->extra;
char s[200], esc[96];
lwsl_notice("%s: registration email sent: %s\n", __func__, username);
/* mark the user as having sent the verification email */
lws_snprintf(s, sizeof(s) - 1,
"update users set verified=1 where username='%s' and verified==0;",
lws_sql_purify(esc, username, sizeof(esc) - 1));
if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
lwsl_err("%s: Unable to update user: %s\n", __func__,
sqlite3_errmsg(vhd->pdb));
return 1;
}
free(e);
return 0;
}
#endif
/* 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[90];
struct lws_gs_event_args a;
struct lwsgs_user u;
if (lws_hdr_copy_fragment(wsi, cookie, sizeof(cookie),
WSI_TOKEN_HTTP_URI_ARGS, 0) < 0) {
lwsl_err("%s: missing URI_ARGS\n", __func__);
goto verf_fail;
}
if (strncmp(cookie, "token=", 6)) {
lwsl_err("%s: missing URI_ARGS token=\n", __func__);
goto verf_fail;
}
u.username[0] = '\0';
u.verified = -1;
lws_snprintf(s, sizeof(s) - 1,
"select username,email,verified from users where token = '%s';",
lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
puts(s);
if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
SQLITE_OK) {
lwsl_err("Unable to lookup token: %s\n",
sqlite3_errmsg(vhd->pdb));
goto verf_fail;
}
if (!u.username[0] || u.verified != 1) {
lwsl_notice("verify token %s doesn't map to unverified user (user='%s', verified=%d)\n",
&cookie[6], u.username, u.verified);
goto verf_fail;
}
lwsl_notice("Verifying %s\n", u.username);
lws_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_vhost(lws_get_vhost(wsi),
LWS_CALLBACK_GS_EVENT, &a, 0);
lws_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;
lws_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[96];
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';
lws_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 */
lws_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";
lws_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";
lws_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,
const char *in)
{
static const char * const colname[] = { "username", "email" };
char s[256], esc[96], *pc;
unsigned char *p, *start, *end, buffer[LWS_PRE + 1024];
struct lwsgs_user u;
int n;
/*
* either /check/email=xxx@yyy or: /check/username=xxx
* returns '0' if not already registered, else '1'
*/
u.username[0] = '\0';
n = !strncmp(in, "email=", 6);
pc = strchr(in, '=');
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;
}
lws_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, HTTP_STATUS_OK, &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 %ld\n", n, (long)(p - start));
return -1;
}
pss->check_response_value = s[0];
pss->check_response = 1;
lws_callback_on_writable(wsi);
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[96], username[96];
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 > (time_t)lws_now_secs() - 300) {
n |= LWSGS_AUTH_FORGOT_FLOW;
lwsl_debug("within forgot password flow\n");
}
}
}
lwsl_debug("auth value %d\n", n);
/* if he just did forgot pw flow, don't need old pw */
if ((n & (LWSGS_AUTH_FORGOT_FLOW | 1)) != (LWSGS_AUTH_FORGOT_FLOW | 1)) {
/* otherwise user:pass must be right */
lwsl_debug("checking pw\n");
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;
}
lwsl_debug("current pw checks out\n");
lws_strncpy(u.username, lws_spa_get_string(pss->spa, FGS_USERNAME),
sizeof(u.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_vhost(lws_get_vhost(wsi),
LWS_CALLBACK_GS_EVENT, &a, 0);
lws_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");
lws_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 esc[96], esc1[96], esc2[96], esc3[96], esc4[96];
char s[LWSGS_EMAIL_CONTENT_SIZE];
unsigned char sid_rand[32];
#if defined(LWS_WITH_SMTP)
lws_smtp_email_t *em;
#endif
struct lwsgs_user u;
lwsgw_hash hash;
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))
lws_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
lws_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;
}
sha256_to_lwsgw_hash(sid_rand, &hash);
lws_snprintf(s, sizeof(s) - 1,
"update users set token='%s',token_time='%ld' where username='%s';",
hash.id, (long)lws_now_secs(),
lws_sql_purify(esc, u.username, sizeof(esc) - 1));
if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) !=
SQLITE_OK) {
lwsl_err("Unable to set token: %s\n",
sqlite3_errmsg(vhd->pdb));
return 1;
}
n = lws_snprintf(s, sizeof(s),
"From: Forgot Password Assistant Noreply <%s>\n"
"To: %s <%s>\n"
"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_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));
lws_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);
puts(s);
#if defined(LWS_WITH_SMTP)
em = lws_smtpc_alloc_email_helper(s, n, vhd->email_from, u.email,
u.username, strlen(u.username),
vhd, lwsgs_smtp_client_done);
if (!em)
return 1;
if (lws_smtpc_add_email(vhd->smtp_client, em))
return 1;
#endif
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[96], esc1[96], esc2[96], esc3[96], esc4[96];
char s[LWSGS_EMAIL_CONTENT_SIZE];
unsigned char sid_rand[32];
#if defined(LWS_WITH_SMTP)
lws_smtp_email_t *em;
#endif
struct lwsgs_user u;
lwsgw_hash hash;
size_t n;
lwsl_notice("REGISTER %s %s %s\n",
lws_spa_get_string(pss->spa, FGS_USERNAME),
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';
lws_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;
}
sha256_to_lwsgw_hash(sid_rand, &hash);
lws_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;
}
n = lws_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_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);
#if defined(LWS_WITH_SMTP)
em = lws_smtpc_alloc_email_helper(s, n, vhd->email_from,
lws_spa_get_string(pss->spa, FGS_EMAIL),
lws_spa_get_string(pss->spa, FGS_USERNAME),
strlen(lws_spa_get_string(pss->spa, FGS_USERNAME)),
vhd, lwsgs_smtp_client_done_sentvfy);
if (!em)
return 1;
if (lws_smtpc_add_email(vhd->smtp_client, em))
return 1;
#else
(void)n;
#endif
return 0;
}

View file

@ -1,171 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#define LWS_DLL
#define LWS_INTERNAL
#include <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 {
lws_abs_t *smtp_client;
struct lwsgs_user u;
lws_token_map_t transport_tokens[3];
lws_token_map_t protocol_tokens[2];
char helo[64], ip[64];
struct lws_context *context;
char session_db[256];
char admin_user[32];
char urlroot[48];
char confounder[32];
char email_contact_person[128];
char email_title[128];
char email_template[128];
char email_confirm_url[128];
char email_from[128];
lwsgw_hash admin_password_sha256;
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 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;
char check_response_value;
unsigned int logging_out:1;
unsigned int check_response: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
sha256_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, const char *in);
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);

View file

@ -1,920 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "private-lwsgs.h"
#include <stdlib.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[];
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[96], 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;
}
lws_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");
lws_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
lws_get_effective_host(struct lws *wsi, char *buf, size_t buflen)
{
#if defined(LWS_ROLE_H2)
/* h2 */
if (lws_hdr_copy(wsi, buf, buflen - 1,
WSI_TOKEN_HTTP_COLON_AUTHORITY) > 0)
return 0;
#endif
/* h1 */
if (lws_hdr_copy(wsi, buf, buflen - 1, WSI_TOKEN_HOST) > 0)
return 0;
return 1;
}
static int
callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
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),
lws_vhost_name_to_protocol(lws_get_vhost(wsi),
"protocol-generic-sessions"));
char cookie[1024], username[32], *pc = cookie;
unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
struct lws_process_html_args *args = in;
struct lws_session_info *sinfo;
char s[LWSGS_EMAIL_CONTENT_SIZE];
unsigned char *p, *start, *end;
const char *cp, *cp1;
sqlite3_stmt *sm;
lwsgw_hash sid;
#if defined(LWS_WITH_SMTP)
lws_abs_t abs;
#endif
int n;
switch (reason) {
case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
lws_get_protocol(wsi), sizeof(struct per_vhost_data__gs));
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->helo, "unconfigured.com");
strcpy(vhd->ip, "127.0.0.1");
strcpy(vhd->email_from, "noreply@unconfigured.com");
strcpy(vhd->email_title, "Registration Email from unconfigured");
vhd->urlroot[0] = '\0';
pvo = (const struct lws_protocol_vhost_options *)in;
while (pvo) {
if (!strcmp(pvo->name, "admin-user"))
lws_strncpy(vhd->admin_user, pvo->value,
sizeof(vhd->admin_user));
if (!strcmp(pvo->name, "urlroot"))
lws_strncpy(vhd->urlroot, pvo->value,
sizeof(vhd->urlroot));
if (!strcmp(pvo->name, "admin-password-sha256"))
lws_strncpy(vhd->admin_password_sha256.id, pvo->value,
sizeof(vhd->admin_password_sha256.id));
if (!strcmp(pvo->name, "session-db"))
lws_strncpy(vhd->session_db, pvo->value,
sizeof(vhd->session_db));
if (!strcmp(pvo->name, "confounder"))
lws_strncpy(vhd->confounder, pvo->value,
sizeof(vhd->confounder));
if (!strcmp(pvo->name, "email-from"))
lws_strncpy(vhd->email_from, pvo->value,
sizeof(vhd->email_from));
if (!strcmp(pvo->name, "email-helo"))
lws_strncpy(vhd->helo, pvo->value, sizeof(vhd->helo));
if (!strcmp(pvo->name, "email-template"))
lws_strncpy(vhd->email_template, pvo->value,
sizeof(vhd->email_template));
if (!strcmp(pvo->name, "email-title"))
lws_strncpy(vhd->email_title, pvo->value,
sizeof(vhd->email_title));
if (!strcmp(pvo->name, "email-contact-person"))
lws_strncpy(vhd->email_contact_person, pvo->value,
sizeof(vhd->email_contact_person));
if (!strcmp(pvo->name, "email-confirm-url-base"))
lws_strncpy(vhd->email_confirm_url, pvo->value,
sizeof(vhd->email_confirm_url));
if (!strcmp(pvo->name, "email-server-ip"))
lws_strncpy(vhd->ip, pvo->value, sizeof(vhd->ip));
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_sha256.id[0] ||
!vhd->session_db[0]) {
lwsl_err("generic-sessions: "
"You must give \"admin-user\", "
"\"admin-password-sha256\", "
"and \"session_db\" per-vhost options\n");
return 1;
}
if (lws_struct_sq3_open(lws_get_context(wsi),
vhd->session_db, 1, &vhd->pdb)) {
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(65),"
" 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(65),"
" pwsalt varchar(65),"
" pwchange_time integer,"
" token varchar(65),"
" 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;
}
#if defined(LWS_WITH_SMTP)
memset(&abs, 0, sizeof(abs));
abs.vh = lws_get_vhost(wsi);
/* select the protocol and bind its tokens */
abs.ap = lws_abs_protocol_get_by_name("smtp");
if (!abs.ap)
return 1;
vhd->protocol_tokens[0].name_index = LTMI_PSMTP_V_HELO;
vhd->protocol_tokens[0].u.value = vhd->helo;
abs.ap_tokens = vhd->protocol_tokens;
/* select the transport and bind its tokens */
abs.at = lws_abs_transport_get_by_name("raw_skt");
if (!abs.at)
return 1;
vhd->transport_tokens[0].name_index = LTMI_PEER_V_DNS_ADDRESS;
vhd->transport_tokens[0].u.value = vhd->ip;
vhd->transport_tokens[1].name_index = LTMI_PEER_LV_PORT;
vhd->transport_tokens[1].u.lvalue = 25;
abs.at_tokens = vhd->transport_tokens;
vhd->smtp_client = lws_abs_bind_and_create_instance(&abs);
if (!vhd->smtp_client)
return 1;
lwsl_notice("%s: created SMTP client\n", __func__);
#endif
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
// lwsl_notice("gs: LWS_CALLBACK_PROTOCOL_DESTROY: v=%p, ctx=%p\n", vhd, vhd->context);
if (vhd->pdb) {
sqlite3_close(vhd->pdb);
vhd->pdb = NULL;
}
#if defined(LWS_WITH_SMTP)
if (vhd->smtp_client)
lws_abs_destroy_instance(&vhd->smtp_client);
#endif
break;
case LWS_CALLBACK_HTTP_WRITEABLE:
if (!pss->check_response)
break;
pss->check_response = 0;
n = lws_write(wsi, (unsigned char *)&pss->check_response_value,
1, LWS_WRITE_HTTP | LWS_WRITE_H2_STREAM_END);
if (n != 1)
return -1;
goto try_to_reuse;
case LWS_CALLBACK_HTTP:
if (!pss) {
lwsl_err("%s: no valid pss\n", __func__);
return 1;
}
pss->login_session.id[0] = '\0';
pss->phs.pos = 0;
cp = in;
if ((*(const char *)in == '/'))
cp++;
if (lws_get_effective_host(wsi, cookie, sizeof(cookie))) {
lwsl_err("%s: HTTP: no effective host\n", __func__);
return 1;
}
lwsl_notice("LWS_CALLBACK_HTTP: %s, HOST '%s'\n",
(const char *)in, cookie);
n = strlen(cp);
lws_snprintf(pss->onward, sizeof(pss->onward),
"%s%s", vhd->urlroot, (const char *)in);
if (n >= 12 &&
!strcmp(cp + n - 12, "lwsgs-forgot")) {
lwsgs_handler_forgot(vhd, wsi, pss);
goto redirect_with_cookie;
}
if (n >= 13 &&
!strcmp(cp + n - 13, "lwsgs-confirm")) {
lwsgs_handler_confirm(vhd, wsi, pss);
goto redirect_with_cookie;
}
cp1 = strstr(cp, "lwsgs-check/");
if (cp1) {
lwsgs_handler_check(vhd, wsi, pss, cp1 + 12);
/* second, async part will complete transaction */
break;
}
if (n >= 11 && cp && !strcmp(cp + n - 11, "lwsgs-login"))
break;
if (n >= 12 && cp && !strcmp(cp + n - 12, "lwsgs-logout"))
break;
if (n >= 12 && cp && !strcmp(cp + n - 12, "lwsgs-forgot"))
break;
if (n >= 12 && cp && !strcmp(cp + n - 12, "lwsgs-change"))
break;
/* if no legitimate url for GET, return 404 */
lwsl_err("%s: http doing 404 on %s\n", __func__, cp ? cp : "null");
lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
return -1;
//goto try_to_reuse;
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
args = (struct lws_process_html_args *)in;
if (!args->chunked)
break;
case LWS_CALLBACK_CHECK_ACCESS_RIGHTS:
n = 0;
username[0] = '\0';
sid.id[0] = '\0';
args = (struct lws_process_html_args *)in;
lwsl_notice("%s: LWS_CALLBACK_CHECK_ACCESS_RIGHTS: need 0x%x\n",
__func__, args->max_len);
if (!lwsgs_get_sid_from_wsi(wsi, &sid)) {
if (lwsgs_lookup_session(vhd, &sid, username,
sizeof(username))) {
/*
* if we're authenticating for ws, we don't
* want to redirect it or gain a cookie on that,
* he'll need to get the cookie from http
* interactions outside of this.
*/
if (args->chunked) {
lwsl_notice("%s: ws auth failed\n",
__func__);
return 1;
}
lwsl_notice("session lookup for %s failed, "
"probably expired\n", sid.id);
pss->delete_session = sid;
args->final = 1; /* signal we dealt with it */
lws_snprintf(pss->onward, sizeof(pss->onward) - 1,
"%s%s", vhd->urlroot, args->p);
lwsl_notice("redirecting to ourselves with "
"cookie refresh\n");
/* we need a redirect to ourselves,
* session cookie is expired */
goto redirect_with_cookie;
}
} else
lwsl_notice("%s: failed to get sid from wsi\n", __func__);
n = lwsgs_get_auth_level(vhd, username);
lwsl_notice("%s: lwsgs_get_auth_level '%s' says %d\n", __func__, username, n);
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;
lws_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;
}
lws_strncpy(sinfo->username, u.username, sizeof(sinfo->username));
lws_strncpy(sinfo->email, u.email, sizeof(sinfo->email));
lws_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 = LWS_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) {
lwsl_err("%s: HTTP_BODY: len %d < 2\n", __func__, (int)len);
break;
}
if (!pss->spa) {
pss->spa = lws_spa_create(wsi, param_names,
LWS_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:
lwsl_debug("%s: LWS_CALLBACK_HTTP_BODY_COMPLETION\n", __func__);
if (!pss->spa)
break;
cp1 = (const char *)pss->onward;
if (*cp1 == '/')
cp1++;
lws_spa_finalize(pss->spa);
n = strlen(cp1);
if (lws_get_effective_host(wsi, cookie, sizeof(cookie)))
return 1;
if (!strcmp(cp1 + n - 12, "lwsgs-change")) {
if (!lwsgs_handler_change_password(vhd, wsi, pss)) {
cp = lws_spa_get_string(pss->spa, FGS_GOOD);
goto pass;
}
cp = lws_spa_get_string(pss->spa, FGS_BAD);
lwsl_notice("user/password no good %s\n",
lws_spa_get_string(pss->spa, FGS_USERNAME));
lws_snprintf(pss->onward, sizeof(pss->onward),
"%s%s", vhd->urlroot, cp);
pss->onward[sizeof(pss->onward) - 1] = '\0';
goto completion_flow;
}
if (!strcmp(cp1 + n - 11, "lwsgs-login")) {
lwsl_err("%s: lwsgs-login\n", __func__);
if (lws_spa_get_string(pss->spa, FGS_FORGOT) &&
lws_spa_get_string(pss->spa, FGS_FORGOT)[0]) {
if (lwsgs_handler_forgot_pw_form(vhd, wsi, pss)) {
n = FGS_FORGOT_BAD;
goto reg_done;
}
#if defined(LWS_WITH_SMTP)
/* get the email monitor to take a look */
lws_smtpc_kick(vhd->smtp_client);
#endif
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;
#if defined(LWS_WITH_SMTP)
/* get the email monitor to take a look */
lws_smtpc_kick(vhd->smtp_client);
#endif
}
reg_done:
lws_snprintf(pss->onward, sizeof(pss->onward),
"%s%s", vhd->urlroot,
lws_spa_get_string(pss->spa, n));
pss->login_expires = 0;
pss->logging_out = 1;
goto completion_flow;
}
/* 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_notice("pw hash check met\n");
cp = lws_spa_get_string(pss->spa, FGS_GOOD);
goto pass;
} else
lwsl_notice("user/password no good %s %s\n",
lws_spa_get_string(pss->spa, FGS_USERNAME),
lws_spa_get_string(pss->spa, FGS_PASSWORD));
if (!lws_spa_get_string(pss->spa, FGS_BAD)) {
lwsl_info("No admin or good target url in form\n");
return -1;
}
lws_snprintf(pss->onward, sizeof(pss->onward),
"%s%s", vhd->urlroot,
lws_spa_get_string(pss->spa, FGS_BAD));
lwsl_notice("failed: %s\n", pss->onward);
goto completion_flow;
}
if (!strcmp(cp1 + n - 12, "lwsgs-logout")) {
lwsl_notice("/logout\n");
if (lwsgs_get_sid_from_wsi(wsi, &pss->login_session)) {
lwsl_notice("not logged in...\n");
return 1;
}
/*
* We keep the same session, but mark it as not
* being associated to any authenticated user
*/
lwsgw_update_session(vhd, &pss->login_session, "");
if (!lws_spa_get_string(pss->spa, FGS_GOOD)) {
lwsl_info("No admin or good target url in form\n");
return -1;
}
lws_snprintf(pss->onward, sizeof(pss->onward),
"%s%s", vhd->urlroot,
lws_spa_get_string(pss->spa, FGS_GOOD));
pss->login_expires = 0;
pss->logging_out = 1;
goto completion_flow;
}
break;
pass:
lws_snprintf(pss->onward, sizeof(pss->onward),
"%s%s", vhd->urlroot, cp);
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_notice("%s: Creating new session: %s\n", __func__,
pss->login_session.id);
} else {
/*
* we can just update the existing session to be
* authorized
*/
lwsl_notice("%s: Authorizing existing session %s, name %s\n",
__func__, sid.id,
lws_spa_get_string(pss->spa, FGS_USERNAME));
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 && pss->spa) {
lws_spa_destroy(pss->spa);
pss->spa = NULL;
}
break;
case LWS_CALLBACK_ADD_HEADERS:
lwsgw_expire_old_sessions(vhd);
lwsl_warn("ADD_HEADERS\n");
args = (struct lws_process_html_args *)in;
if (!pss)
return 1;
if (pss->delete_session.id[0]) {
pc = cookie;
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,
(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;
lwsl_warn("%s: redirect_with_cookie\n", __func__);
if (lws_add_http_header_status(wsi, HTTP_STATUS_SEE_OTHER, &p, end))
return 1;
{
char loc[1024], uria[128];
uria[0] = '\0';
lws_hdr_copy_fragment(wsi, uria, sizeof(uria),
WSI_TOKEN_HTTP_URI_ARGS, 0);
n = lws_snprintf(loc, sizeof(loc), "%s?%s",
pss->onward, uria);
lwsl_notice("%s: redirect to '%s'\n", __func__, loc);
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION,
(unsigned char *)loc, n, &p, end))
return 1;
}
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
(unsigned char *)"text/html", 9, &p, end))
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)) {
lwsl_err("fail0\n");
return 1;
}
}
if (!pss->login_session.id[0]) {
pss->login_expires = lws_now_secs() +
vhd->timeout_anon_absolute_secs;
if (lwsgs_new_session_id(vhd, &pss->login_session, "",
pss->login_expires)) {
lwsl_err("fail1\n");
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_err("%s: setting cookie '%s'\n", __func__, cookie);
pss->logging_out = 0;
if (lws_add_http_header_by_name(wsi,
(unsigned char *)"set-cookie:",
(unsigned char *)cookie, pc - cookie,
&p, end)) {
lwsl_err("fail2\n");
return 1;
}
}
if (lws_finalize_http_header(wsi, &p, end))
return 1;
// lwsl_hexdump_notice(start, p - start);
n = lws_write(wsi, start, p - start, LWS_WRITE_H2_STREAM_END |
LWS_WRITE_HTTP_HEADERS);
if (n < 0)
return 1;
/* 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_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 = LWS_ARRAY_SIZE(protocols);
c->extensions = NULL;
c->count_extensions = 0;
return 0;
}
LWS_VISIBLE int
destroy_protocol_generic_sessions(struct lws_context *context)
{
return 0;
}

View file

@ -1,438 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#define LWS_DLL
#define LWS_INTERNAL
#include <libwebsockets.h>
#include <sqlite3.h>
#include <string.h>
#include <stdlib.h>
struct per_vhost_data__gs_mb {
struct lws_vhost *vh;
const struct lws_protocols *gsp;
sqlite3 *pdb;
char message_db[256];
unsigned long last_idx;
};
struct per_session_data__gs_mb {
void *pss_gs; /* for use by generic-sessions */
struct lws_session_info sinfo;
struct lws_spa *spa;
unsigned long last_idx;
unsigned int our_form:1;
char second_http_part;
};
static const char * const param_names[] = {
"send",
"msg",
};
enum {
MBSPA_SUBMIT,
MBSPA_MSG,
};
#define MAX_MSG_LEN 512
struct message {
unsigned long idx;
unsigned long time;
char username[32];
char email[100];
char ip[72];
char content[MAX_MSG_LEN];
};
static int
lookup_cb(void *priv, int cols, char **col_val, char **col_name)
{
struct message *m = (struct message *)priv;
int n;
for (n = 0; n < cols; n++) {
if (!strcmp(col_name[n], "idx") ||
!strcmp(col_name[n], "MAX(idx)")) {
if (!col_val[n])
m->idx = 0;
else
m->idx = atol(col_val[n]);
continue;
}
if (!strcmp(col_name[n], "time")) {
m->time = atol(col_val[n]);
continue;
}
if (!strcmp(col_name[n], "username")) {
lws_strncpy(m->username, col_val[n], sizeof(m->username));
continue;
}
if (!strcmp(col_name[n], "email")) {
lws_strncpy(m->email, col_val[n], sizeof(m->email));
continue;
}
if (!strcmp(col_name[n], "ip")) {
lws_strncpy(m->ip, col_val[n], sizeof(m->ip));
continue;
}
if (!strcmp(col_name[n], "content")) {
lws_strncpy(m->content, col_val[n], sizeof(m->content));
continue;
}
}
return 0;
}
static unsigned long
get_last_idx(struct per_vhost_data__gs_mb *vhd)
{
struct message m;
if (sqlite3_exec(vhd->pdb, "SELECT MAX(idx) FROM msg;",
lookup_cb, &m, NULL) != SQLITE_OK) {
lwsl_err("Unable to lookup token: %s\n",
sqlite3_errmsg(vhd->pdb));
return 0;
}
return m.idx;
}
static int
post_message(struct lws *wsi, struct per_vhost_data__gs_mb *vhd,
struct per_session_data__gs_mb *pss)
{
struct lws_session_info sinfo;
char s[MAX_MSG_LEN + 512];
char esc[MAX_MSG_LEN + 256];
vhd->gsp->callback(wsi, LWS_CALLBACK_SESSION_INFO,
pss->pss_gs, &sinfo, 0);
lws_snprintf((char *)s, sizeof(s) - 1,
"insert into msg(time, username, email, ip, content)"
" values (%lu, '%s', '%s', '%s', '%s');",
(unsigned long)lws_now_secs(), sinfo.username, sinfo.email, sinfo.ip,
lws_sql_purify(esc, lws_spa_get_string(pss->spa, MBSPA_MSG),
sizeof(esc) - 1));
if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
lwsl_err("Unable to insert msg: %s\n", sqlite3_errmsg(vhd->pdb));
return 1;
}
vhd->last_idx = get_last_idx(vhd);
/* let everybody connected by this protocol on this vhost know */
lws_callback_on_writable_all_protocol_vhost(lws_get_vhost(wsi),
lws_get_protocol(wsi));
return 0;
}
static int
callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
struct per_session_data__gs_mb *pss = (struct per_session_data__gs_mb *)user;
const struct lws_protocol_vhost_options *pvo;
struct per_vhost_data__gs_mb *vhd = (struct per_vhost_data__gs_mb *)
lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi));
unsigned char *p, *start, *end, buffer[LWS_PRE + 4096];
char s[512];
int n;
switch (reason) {
case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
lws_get_protocol(wsi), sizeof(struct per_vhost_data__gs_mb));
if (!vhd)
return 1;
vhd->vh = lws_get_vhost(wsi);
vhd->gsp = lws_vhost_name_to_protocol(vhd->vh,
"protocol-generic-sessions");
if (!vhd->gsp) {
lwsl_err("messageboard: requires generic-sessions\n");
return 1;
}
pvo = (const struct lws_protocol_vhost_options *)in;
while (pvo) {
if (!strcmp(pvo->name, "message-db"))
strncpy(vhd->message_db, pvo->value,
sizeof(vhd->message_db) - 1);
pvo = pvo->next;
}
if (!vhd->message_db[0]) {
lwsl_err("messageboard: \"message-db\" pvo missing\n");
return 1;
}
if (lws_struct_sq3_open(lws_get_context(wsi),
vhd->message_db, 1, &vhd->pdb)) {
lwsl_err("Unable to open message db %s: %s\n",
vhd->message_db, sqlite3_errmsg(vhd->pdb));
return 1;
}
if (sqlite3_exec(vhd->pdb, "create table if not exists msg ("
" idx integer primary key, time integer,"
" username varchar(32), email varchar(100),"
" ip varchar(80), content blob);",
NULL, NULL, NULL) != SQLITE_OK) {
lwsl_err("Unable to create msg table: %s\n",
sqlite3_errmsg(vhd->pdb));
return 1;
}
vhd->last_idx = get_last_idx(vhd);
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
if (vhd && vhd->pdb)
sqlite3_close(vhd->pdb);
goto passthru;
case LWS_CALLBACK_ESTABLISHED:
vhd->gsp->callback(wsi, LWS_CALLBACK_SESSION_INFO,
pss->pss_gs, &pss->sinfo, 0);
if (!pss->sinfo.username[0]) {
lwsl_notice("messageboard ws attempt with no session\n");
return -1;
}
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_CLOSED:
lwsl_debug("%s: LWS_CALLBACK_CLOSED\n", __func__);
if (pss && pss->pss_gs) {
free(pss->pss_gs);
pss->pss_gs = NULL;
}
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
{
struct message m;
char j[MAX_MSG_LEN + 512], e[MAX_MSG_LEN + 512],
*p = j + LWS_PRE, *start = p,
*end = j + sizeof(j) - LWS_PRE;
if (pss->last_idx == vhd->last_idx)
break;
/* restrict to last 10 */
if (!pss->last_idx)
if (vhd->last_idx >= 10)
pss->last_idx = vhd->last_idx - 10;
sprintf(s, "select idx, time, username, email, ip, content "
"from msg where idx > %lu order by idx limit 1;",
pss->last_idx);
if (sqlite3_exec(vhd->pdb, s, lookup_cb, &m, NULL) != SQLITE_OK) {
lwsl_err("Unable to lookup msg: %s\n",
sqlite3_errmsg(vhd->pdb));
return 0;
}
/* format in JSON */
p += lws_snprintf(p, end - p,
"{\"idx\":\"%lu\",\"time\":\"%lu\",",
m.idx, m.time);
p += lws_snprintf(p, end - p, " \"username\":\"%s\",",
lws_json_purify(e, m.username, sizeof(e), NULL));
p += lws_snprintf(p, end - p, " \"email\":\"%s\",",
lws_json_purify(e, m.email, sizeof(e), NULL));
p += lws_snprintf(p, end - p, " \"ip\":\"%s\",",
lws_json_purify(e, m.ip, sizeof(e), NULL));
p += lws_snprintf(p, end - p, " \"content\":\"%s\"}",
lws_json_purify(e, m.content, sizeof(e), NULL));
if (lws_write(wsi, (unsigned char *)start, p - start,
LWS_WRITE_TEXT) < 0)
return -1;
pss->last_idx = m.idx;
if (pss->last_idx == vhd->last_idx)
break;
lws_callback_on_writable(wsi); /* more to do */
}
break;
case LWS_CALLBACK_HTTP:
pss->our_form = 0;
/* ie, it's our messageboard new message form */
if (!strcmp((const char *)in, "/msg") ||
!strcmp((const char *)in, "msg")) {
pss->our_form = 1;
break;
}
goto passthru;
case LWS_CALLBACK_HTTP_BODY:
if (!pss->our_form)
goto passthru;
if (len < 2)
break;
if (!pss->spa) {
pss->spa = lws_spa_create(wsi, param_names,
LWS_ARRAY_SIZE(param_names),
MAX_MSG_LEN + 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_WRITEABLE:
if (!pss->second_http_part)
goto passthru;
s[0] = '0';
n = lws_write(wsi, (unsigned char *)s, 1, LWS_WRITE_HTTP|
LWS_WRITE_H2_STREAM_END);
if (n != 1)
return -1;
goto try_to_reuse;
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
if (!pss->our_form)
goto passthru;
if (post_message(wsi, vhd, pss))
return -1;
p = buffer + LWS_PRE;
start = p;
end = p + sizeof(buffer) - LWS_PRE;
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &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 %ld\n", n, (long)(p - start));
return -1;
}
pss->second_http_part = 1;
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_HTTP_BIND_PROTOCOL:
if (!pss || !vhd || 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->spa) {
lws_spa_destroy(pss->spa);
pss->spa = NULL;
}
if (pss && pss->pss_gs) {
free(pss->pss_gs);
pss->pss_gs = NULL;
}
break;
default:
passthru:
if (!pss || !vhd)
break;
return vhd->gsp->callback(wsi, reason, pss->pss_gs, in, len);
}
return 0;
try_to_reuse:
if (lws_http_transaction_completed(wsi))
return -1;
return 0;
}
static const struct lws_protocols protocols[] = {
{
"protocol-lws-messageboard",
callback_messageboard,
sizeof(struct per_session_data__gs_mb),
4096,
},
};
LWS_VISIBLE int
init_protocol_lws_messageboard(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 = LWS_ARRAY_SIZE(protocols);
c->extensions = NULL;
c->count_extensions = 0;
return 0;
}
LWS_VISIBLE int
destroy_protocol_lws_messageboard(struct lws_context *context)
{
return 0;
}

View file

@ -1,465 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "private-lwsgs.h"
#include <stdlib.h>
void
sha256_to_lwsgw_hash(unsigned char *hash, lwsgw_hash *shash)
{
static const char *hex = "0123456789abcdef";
char *p = shash->id;
int n;
for (n = 0; n < (int)lws_genhash_size(LWS_GENHASH_TYPE_SHA256); n++) {
*p++ = hex[(hash[n] >> 4) & 0xf];
*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);
sha256_to_lwsgw_hash(hash_bin.bin, &pw_hash);
return !strcmp(vhd->admin_password_sha256.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 += lws_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 += lws_snprintf(*p, end - *p, ";path=/");
*p += lws_snprintf(*p, end - *p, ";Max-Age=%lu", (unsigned long)(expires - n));
// *p += lws_snprintf(*p, end - *p, ";secure");
*p += lws_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;
lws_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[96], esc1[96];
if (user[0])
n += vhd->timeout_absolute_secs;
else
n += vhd->timeout_anon_absolute_secs;
lws_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;
}
puts(s);
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 < (int)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 < (int)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("%s: session from cookie failed\n", __func__);
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]) {
lws_strncpy(lla->username, col_val[0], lla->len + 1);
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[96];
lwsgw_expire_old_sessions(vhd);
lws_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")) {
lws_strncpy(u->username, col_val[n], sizeof(u->username));
continue;
}
if (!strcmp(col_name[n], "ip")) {
lws_strncpy(u->ip, col_val[n], sizeof(u->ip));
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")) {
lws_strncpy(u->email, col_val[n], sizeof(u->email));
continue;
}
if (!strcmp(col_name[n], "verified")) {
u->verified = atoi(col_val[n]);
continue;
}
if (!strcmp(col_name[n], "pwhash")) {
lws_strncpy(u->pwhash.id, col_val[n], sizeof(u->pwhash.id));
continue;
}
if (!strcmp(col_name[n], "pwsalt")) {
lws_strncpy(u->pwsalt.id, col_val[n], sizeof(u->pwsalt.id));
continue;
}
if (!strcmp(col_name[n], "token")) {
lws_strncpy(u->token.id, col_val[n], sizeof(u->token.id));
continue;
}
}
return 0;
}
int
lwsgs_lookup_user(struct per_vhost_data__gs *vhd,
const char *username, struct lwsgs_user *u)
{
char s[150], esc[96];
u->username[0] = '\0';
lws_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[32];
const char *u;
char s[300], esc[96], esc1[96];
if (username)
u = username;
else
u = "";
if (!sid) {
lwsl_err("%s: NULL sid\n", __func__);
return 1;
}
memset(sid, 0, sizeof(*sid));
if (lws_get_random(vhd->context, sid_rand, sizeof(sid_rand)) !=
sizeof(sid_rand))
return 1;
sha256_to_lwsgw_hash(sid_rand, sid);
lws_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;
}
lwsl_notice("%s: created session %s\n", __func__, sid->id);
return 0;
}
int
lwsgs_get_auth_level(struct per_vhost_data__gs *vhd, const char *username)
{
struct lwsgs_user u;
int n = 0;
/* we are logged in as some kind of user */
if (username[0]) {
/* we are logged in as admin */
if (!strcmp(username, vhd->admin_user))
/* automatically verified */
n |= LWSGS_AUTH_VERIFIED | LWSGS_AUTH_ADMIN;
}
if (!lwsgs_lookup_user(vhd, username, &u)) {
if ((u.verified & 0xff) == LWSGS_VERIFIED_ACCEPTED)
n |= LWSGS_AUTH_LOGGED_IN | LWSGS_AUTH_VERIFIED;
if (u.last_forgot_validated > (time_t)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)
{
struct lws_genhash_ctx hash_ctx;
lwsgw_hash_bin hash_bin;
struct lwsgs_user u;
lwsgw_hash hash;
if (lwsgs_lookup_user(vhd, username, &u))
return -1;
lwsl_info("user %s found, salt '%s'\n", username, u.pwsalt.id);
/* sha256sum of password + salt */
if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256) ||
lws_genhash_update(&hash_ctx, password, strlen(password)) ||
lws_genhash_update(&hash_ctx, "-", 1) ||
lws_genhash_update(&hash_ctx, vhd->confounder, strlen(vhd->confounder)) ||
lws_genhash_update(&hash_ctx, "-", 1) ||
lws_genhash_update(&hash_ctx, u.pwsalt.id, strlen(u.pwsalt.id)) ||
lws_genhash_destroy(&hash_ctx, hash_bin.bin)) {
lws_genhash_destroy(&hash_ctx, NULL);
return 1;
}
sha256_to_lwsgw_hash(&hash_bin.bin[0], &hash);
return !!strcmp(hash.id, u.pwhash.id);
}
/* sets u->pwsalt and u->pwhash */
int
lwsgs_hash_password(struct per_vhost_data__gs *vhd,
const char *password, struct lwsgs_user *u)
{
unsigned char sid_rand[32];
struct lws_genhash_ctx hash_ctx;
lwsgw_hash_bin hash_bin;
/* 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;
}
sha256_to_lwsgw_hash(sid_rand, &u->pwsalt);
/*
if (lws_get_random(vhd->context, sid_rand,
sizeof(sid_rand)) !=
sizeof(sid_rand)) {
lwsl_err("Problem getting random for token\n");
return 1;
}
sha256_to_lwsgw_hash(sid_rand, &hash);
*/
/* sha256sum of password + salt */
if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256) ||
lws_genhash_update(&hash_ctx, password, strlen(password)) ||
lws_genhash_update(&hash_ctx, "-", 1) ||
lws_genhash_update(&hash_ctx, vhd->confounder, strlen(vhd->confounder)) ||
lws_genhash_update(&hash_ctx, "-", 1) ||
lws_genhash_update(&hash_ctx, u->pwsalt.id, strlen(u->pwsalt.id)) ||
lws_genhash_destroy(&hash_ctx, hash_bin.bin)) {
lws_genhash_destroy(&hash_ctx, NULL);
return 1;
}
sha256_to_lwsgw_hash(&hash_bin.bin[0], &u->pwhash);
return 0;
}

View file

@ -1,75 +0,0 @@
<html>
<head>
<script src="/lws-common.js"></script>
<script src="lwsgt.js"></script>
<style>
.body { font-size: 12 }
.gstitle { font-size: 24; text-align:center }
.group1 { vertical-align:middle;text-align:center;background:#f0f0e0;
padding:12px; -webkit-border-radius:10px;
-moz-border-radius:10px;border-radius:10px; }
.group2 { vertical-align:middle; font-size: 18;text-align:center;
margin:auto; align:center;
background-color: rgba(255, 255, 255, 0.8); padding:12px;
display:inline-block; -webkit-border-radius:10px;
-moz-border-radius:10px; border-radius:10px; }
.lwsgt_title { font-size: 24; text-align:center }
.lwsgt_breadcrumbs { font-size: 18; text-align:left }
.lwsgt_table { font-size: 14; padding:12px; margin: 12px; align:center }
.lwsgt_hdr { font-size: 18; text-align:center;
background-color: rgba(40, 40, 40, 0.8); color: white }
.lwsgt_tr { padding: 10px }
.lwsgt_td { padding: 3px }
</style>
</head>
<body>
<table>
<tr><td class="gstitle">
LWS Generic Table demo
</td></tr>
<tr><td class="group2">
This is a demo of lws generic table, using a protocol plugin
"protocol-lws-table-dirlisting". It shows a directory listing,
but unlike an oldstyle directory listing done on the
server side with a script, this is static html that connects
back to the server with a websocket, and gets live JSON from
that.
<p>
Actually the static html is extremely simple, since it uses
lwsgt, LWS Generic Table, JS include on the client-side that
handles all the table generation from a template sent in JSON
over the ws link. It means there is no custom JS required
clientside either. It's just CSS, this text and a call to
initialize lwsgt with the appropriate ws protocol.
</td></tr>
<tr><td><div id="lwsgt1" class="group1"></div></td></tr>
<tr><td class="group2">
There's no problem having multiple independent instances per
page...
</td></tr>
<tr><td><div id="lwsgt2" class="group1"></div></td></tr>
</table>
<div id="debug"></div>
<script nonce="lwscaro">
var v1 = new lwsgt_initial("Dir listing demo",
"protocol-lws-table-dirlisting",
"lwsgt1", "lwsgt_dir_click", "v1");
var v2 = new lwsgt_initial("Dir listing 2",
"protocol-lws-table-dirlisting",
"lwsgt2", "lwsgt_dir_click", "v2");
function lwsgt_dir_click(gt, u, col, row)
{
if (u[0] == '=') { /* change directory */
window[gt].lwsgt_ws.send(u.substring(1, u.length));
return;
}
var win = window.open(u, '_blank');
win.focus();
}
</script>
</body>
</html>

View file

@ -1,139 +0,0 @@
function lwsgt_get_appropriate_ws_url()
{
var pcol;
var u = document.URL;
if (u.substring(0, 5) === "https") {
pcol = "wss://";
u = u.substr(8);
} else {
pcol = "ws://";
if (u.substring(0, 4) === "http")
u = u.substr(7);
}
return pcol + u;
}
function lwsgt_app_hdr(j, bc, ws)
{
var s = "", n, m = 0;
ws.bcq = 0;
for (n = 0; n < j.cols.length; n++)
if (!j.cols[n].hide)
m++;
s = "<tr><td colspan=\"" + m + "\" class=\"lwsgt_title\">" +
ws.lwsgt_title + "</td></tr>";
if (!!bc) {
s += "<tr><td colspan=\"" + m + "\" class=\"lwsgt_breadcrumbs\">";
for (n = 0; n < bc.length; n++) {
s += " / ";
if (!bc[n].url && bc[n].url !== "")
s += " " + lws_san(bc[n].name) + " ";
else {
s += "<a href=# id=\"bc_"+ ws.divname + ws.bcq + "\" h=\"" +
ws.lwsgt_cb + "\" p=\""+ws.lwsgt_parent+"\" aa=\"="+
lws_san(encodeURI(bc[n].url))+"\" m=\"-1\" n=\"-1\">" +
lws_san(bc[n].name) + "</a> ";
ws.bcq++;
}
}
s += "</td></tr>";
}
s += "<tr>";
for (n = 0; n < j.cols.length; n++)
if (!j.cols[n].hide)
s = s + "<td class=\"lwsgt_hdr\">" + lws_san(j.cols[n].name) +
"</td>";
s += "</tr>";
return s;
}
function lwsgt_click_callthru()
{
window[this.getAttribute("h")](this.getAttribute("p"), this.getAttribute("aa"), this.getAttribute("m"), this.getAttribute("n"));
event.preventDefault();
}
function lwsgt_initial(title, pcol, divname, cb, gname)
{
this.divname = divname;
lws_gray_out(true,{"zindex":"499"});
this.lwsgt_ws = new WebSocket(lwsgt_get_appropriate_ws_url(), pcol);
this.lwsgt_ws.divname = divname;
this.lwsgt_ws.lwsgt_cb = cb;
this.lwsgt_ws.lwsgt_parent = gname;
this.lwsgt_ws.lwsgt_title = title;
try {
this.lwsgt_ws.onopen = function() {
lws_gray_out(false);
// document.getElementById("debug").textContent =
// "ws opened " + lwsgt_get_appropriate_ws_url();
};
this.lwsgt_ws.onmessage = function got_packet(msg) {
var s, m, n, j = JSON.parse(msg.data);
document.getElementById("debug").textContent = msg.data;
if (j.cols) {
this.hdr = j;
}
if (j.breadcrumbs)
this.breadcrumbs = j.breadcrumbs;
if (j.data) {
var q = 0;
s = "<table class=\"lwsgt_table\">" +
lwsgt_app_hdr(this.hdr, this.breadcrumbs, this);
for (m = 0; m < j.data.length; m++) {
s = s + "<tr class=\"lwsgt_tr\">";
for (n = 0; n < this.hdr.cols.length; n++) {
if (!this.hdr.cols[n].hide) {
if (!this.hdr.cols[n].align)
s = s + "<td class=\"lwsgt_td\">";
else
s = s + "<td class=\"lwsgt_td\" style=\"text-align: right\">";
if (this.hdr.cols[n].href &&
!!j.data[m][this.hdr.cols[n].href]) {
s = s + "<a href=# id=\""+ this.divname + q + "\" h=\"" + this.lwsgt_cb + "\" p=\""+this.lwsgt_parent+"\" aa=\""+
lws_san(encodeURI(j.data[m][this.hdr.cols[n].href]))+"\" m=\""+m+"\" n=\""+n+"\">" +
lws_san(j.data[m][this.hdr.cols[n].name]) +
"</a>";
q++;
}
else
s = s + lws_san(j.data[m][this.hdr.cols[n].name]);
s = s + "</td>";
}
}
s = s + "</tr>";
}
s = s + "</table>";
document.getElementById(this.divname).innerHTML = s;
for (n = 0; n < q; n++)
document.getElementById(this.divname + n).onclick =
lwsgt_click_callthru;
for (n = 0; n < this.bcq; n++)
document.getElementById("bc_" + this.divname + n).onclick =
lwsgt_click_callthru;
}
};
this.lwsgt_ws.onclose = function(){
lws_gray_out(true,{"zindex":"499"});
};
} catch(exception) {
alert("<p>Error" + exception);
}
}

View file

@ -1,397 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#define LWS_DLL
#define LWS_INTERNAL
#include <libwebsockets.h>
#include <stdlib.h>
#include <string.h>
#include <uv.h>
struct fobj {
struct fobj *next;
const char *name, *uri, *icon, *date;
time_t m;
unsigned long size;
};
struct per_session_data__tbl_dir {
struct fobj base;
char strings[64 * 1024];
char reldir[256];
char *p;
const char *dir;
#if UV_VERSION_MAJOR > 0
uv_fs_event_t *event_req;
#endif
struct lws *wsi;
};
#if UV_VERSION_MAJOR > 0
static void
mon_cb(uv_fs_event_t *handle, const char *filename, int events, int status)
{
struct per_session_data__tbl_dir *pss = handle->data;
//lwsl_notice("%s\n", __func__);
if (pss && pss->wsi)
lws_callback_on_writable(pss->wsi);
}
static void lws_uv_close_cb(uv_handle_t *handle)
{
free(handle);
}
static void
lws_protocol_dir_kill_monitor(struct per_session_data__tbl_dir *pss)
{
if (!pss->event_req)
return;
pss->wsi = NULL;
pss->event_req->data = NULL;
uv_fs_event_stop(pss->event_req);
uv_close((uv_handle_t *)pss->event_req, lws_uv_close_cb);
pss->event_req = NULL;
}
#endif
static int
scan_dir(struct lws *wsi, struct per_session_data__tbl_dir *pss)
{
/* uuh travis... */
#if UV_VERSION_MAJOR > 0
uv_loop_t *loop = lws_uv_getloop(lws_get_context(wsi), 0);
char *end = &(pss->strings[sizeof(pss->strings) - 1]);
struct fobj *prev = &pss->base;
char path[512], da[200];
const char *icon;
uv_dirent_t dent;
struct fobj *f;
struct stat st;
struct tm *tm;
int ret = 0, n;
uv_fs_t req;
lws_protocol_dir_kill_monitor(pss);
lws_snprintf(path, sizeof(path) - 1, "%s/%s", pss->dir, pss->reldir);
//lwsl_notice("path = %s\n", path);
pss->event_req = malloc(sizeof(*pss->event_req));
if (!pss->event_req)
return 2;
pss->wsi = wsi;
pss->event_req->data = pss;
uv_fs_event_init(lws_uv_getloop(lws_get_context(wsi), 0),
pss->event_req);
// The recursive flag watches subdirectories too.
n = uv_fs_event_start(pss->event_req, mon_cb, path, UV_FS_EVENT_RECURSIVE);
//lwsl_notice("monitoring %s (%d)\n", path, n);
if (!uv_fs_scandir(loop, &req, path, 0, NULL)) {
lwsl_err("Scandir on %s failed\n", path);
return 2;
}
pss->p = pss->strings;
while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
lws_snprintf(path, sizeof(path) - 1, "%s/%s/%s", pss->dir, pss->reldir, dent.name);
if (stat(path, &st)) {
lwsl_info("unable to stat %s\n", path);
continue;
}
f = malloc(sizeof(*f));
f->next = NULL;
f->name = pss->p;
n = lws_snprintf(pss->p, end - pss->p, "%s", dent.name);
pss->p += n + 1;
f->uri = NULL;
if ((S_IFMT & st.st_mode) == S_IFDIR) {
n = lws_snprintf(pss->p, end - pss->p, "=%s/%s", pss->reldir, dent.name);
f->uri = pss->p;
}
if (lws_get_mimetype(dent.name, NULL)) {
n = lws_snprintf(pss->p, end - pss->p, "./serve/%s/%s", pss->reldir, dent.name);
f->uri = pss->p;
}
if (f->uri)
pss->p += n + 1;
if (end - pss->p < 100) {
free(f);
break;
}
icon = " ";
if ((S_IFMT & st.st_mode) == S_IFDIR)
icon = "&#x1f4c2;";
f->icon = pss->p;
n = lws_snprintf(pss->p, end - pss->p, "%s", icon);
pss->p += n + 1;
f->date = pss->p;
tm = gmtime(&st.st_mtime);
strftime(da, sizeof(da), "%Y-%b-%d %H:%M:%S %z", tm);
n = lws_snprintf(pss->p, end - pss->p, "%s", da);
pss->p += n + 1;
f->size = st.st_size;
f->m = st.st_mtime;
prev->next = f;
prev = f;
}
uv_fs_req_cleanup(&req);
return ret;
#else
return 0;
#endif
}
static void
free_scan_dir(struct per_session_data__tbl_dir *pss)
{
struct fobj *f = pss->base.next, *f1;
while (f) {
f1 = f->next;
free(f);
f = f1;
}
pss->base.next = NULL;
}
static int
callback_lws_table_dirlisting(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
struct per_session_data__tbl_dir *pss = (struct per_session_data__tbl_dir *)user;
char j[LWS_PRE + 16384], *p = j + LWS_PRE, *start = p, *q, *q1, *w,
*end = j + sizeof(j) - LWS_PRE, e[384], s[384], s1[384];
const struct lws_protocol_vhost_options *pmo;
struct fobj *f;
int n, first = 1;
switch (reason) {
case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
break;
case LWS_CALLBACK_ESTABLISHED:
lwsl_debug("LWS_CALLBACK_ESTABLISHED\n");
/*
* send client the lwsgt table layout
*/
start = "{\"cols\":["
" {\"name\": \"Date\"},"
" {\"name\": \"Size\", \"align\": \"right\"},"
" {\"name\": \"Icon\"},"
" {\"name\": \"Name\", \"href\": \"uri\"},"
" {\"name\": \"uri\", \"hide\": \"1\" }"
" ]"
"}";
if (lws_write(wsi, (unsigned char *)start, strlen(start),
LWS_WRITE_TEXT) < 0)
return -1;
/* send a view update next */
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_RECEIVE:
if (len > sizeof(pss->reldir) - 1)
len = sizeof(pss->reldir) - 1;
if (!strstr(in, "..") && !strchr(in, '~'))
lws_strncpy(pss->reldir, in, len + 1);
else
len = 0;
pss->reldir[len] = '\0';
if (pss->reldir[0] == '/' && !pss->reldir[1])
pss->reldir[0] = '\0';
lwsl_info("%s\n", pss->reldir);
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
if (scan_dir(wsi, pss))
return 1;
p += lws_snprintf(p, end - p, "{\"breadcrumbs\":[");
q = pss->reldir;
if (!q[0])
p += lws_snprintf(p, end - p, "{\"name\":\"top\"}");
while (*q) {
q1 = strchr(q, '/');
if (!q1) {
if (first)
strcpy(s, "top1");
else
strcpy(s, q);
s1[0] = '\0';
q += strlen(q);
} else {
n = lws_ptr_diff(q1, q);
if (n > (int)sizeof(s) - 1)
n = sizeof(s) - 1;
if (first) {
strcpy(s1, "/");
strcpy(s, "top");
} else {
lws_strncpy(s, q, n + 1);
n = lws_ptr_diff(q1, pss->reldir);
if (n > (int)sizeof(s1) - 1)
n = sizeof(s1) - 1;
lws_strncpy(s1, pss->reldir, n + 1);
}
q = q1 + 1;
}
if (!first)
p += lws_snprintf(p, end - p, ",");
else
first = 0;
p += lws_snprintf(p, end - p, "{\"name\":\"%s\"",
lws_json_purify(e, s, sizeof(e), NULL));
if (*q) {
w = s1;
while (w[0] == '/' && w[1] == '/')
w++;
p += lws_snprintf(p, end - p, ",\"url\":\"%s\"",
lws_json_purify(e, w, sizeof(e), NULL));
}
p += lws_snprintf(p, end - p, "}");
if (!q1)
break;
}
p += lws_snprintf(p, end - p, "],\"data\":[");
f = pss->base.next;
while (f) {
/* format in JSON */
p += lws_snprintf(p, end - p, "{\"Icon\":\"%s\",",
lws_json_purify(e, f->icon, sizeof(e), NULL));
p += lws_snprintf(p, end - p, " \"Date\":\"%s\",",
lws_json_purify(e, f->date, sizeof(e), NULL));
p += lws_snprintf(p, end - p, " \"Size\":\"%ld\",",
f->size);
if (f->uri)
p += lws_snprintf(p, end - p, " \"uri\":\"%s\",",
lws_json_purify(e, f->uri, sizeof(e), NULL));
p += lws_snprintf(p, end - p, " \"Name\":\"%s\"}",
lws_json_purify(e, f->name, sizeof(e), NULL));
f = f->next;
if (f)
p += lws_snprintf(p, end - p, ",");
}
p += lws_snprintf(p, end - p, "]}");
free_scan_dir(pss);
if (lws_write(wsi, (unsigned char *)start, p - start,
LWS_WRITE_TEXT) < 0)
return -1;
break;
case LWS_CALLBACK_HTTP_PMO:
/* find the per-mount options we're interested in */
lwsl_debug("LWS_CALLBACK_HTTP_PMO\n");
pmo = (struct lws_protocol_vhost_options *)in;
while (pmo) {
if (!strcmp(pmo->name, "dir")) /* path to list files */
pss->dir = pmo->value;
pmo = pmo->next;
}
if (!pss->dir[0]) {
lwsl_err("dirlisting: \"dir\" pmo missing\n");
return 1;
}
break;
case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
//lwsl_notice("LWS_CALLBACK_HTTP_DROP_PROTOCOL\n");
#if UV_VERSION_MAJOR > 0
lws_protocol_dir_kill_monitor(pss);
#endif
break;
default:
return 0;
}
return 0;
}
static const struct lws_protocols protocols[] = {
{
"protocol-lws-table-dirlisting",
callback_lws_table_dirlisting,
sizeof(struct per_session_data__tbl_dir),
0,
},
};
LWS_VISIBLE int
init_protocol_lws_table_dirlisting(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 = LWS_ARRAY_SIZE(protocols);
c->extensions = NULL;
c->count_extensions = 0;
return 0;
}
LWS_VISIBLE int
destroy_protocol_lws_table_dirlisting(struct lws_context *context)
{
return 0;
}