handlers.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /*
  2. * ws protocol handler plugin for "generic sessions"
  3. *
  4. * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation:
  9. * version 2.1 of the License.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. * MA 02110-1301 USA
  20. */
  21. #include "private-lwsgs.h"
  22. /* handle account confirmation links */
  23. int
  24. lwsgs_handler_confirm(struct per_vhost_data__gs *vhd, struct lws *wsi,
  25. struct per_session_data__gs *pss)
  26. {
  27. char cookie[1024], s[256], esc[50];
  28. struct lws_gs_event_args a;
  29. struct lwsgs_user u;
  30. if (lws_hdr_copy_fragment(wsi, cookie, sizeof(cookie),
  31. WSI_TOKEN_HTTP_URI_ARGS, 0) < 0)
  32. goto verf_fail;
  33. if (strncmp(cookie, "token=", 6))
  34. goto verf_fail;
  35. u.username[0] = '\0';
  36. lws_snprintf(s, sizeof(s) - 1,
  37. "select username,email,verified from users where token = '%s';",
  38. lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
  39. if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
  40. SQLITE_OK) {
  41. lwsl_err("Unable to lookup token: %s\n",
  42. sqlite3_errmsg(vhd->pdb));
  43. goto verf_fail;
  44. }
  45. if (!u.username[0] || u.verified != 1) {
  46. lwsl_notice("verify token doesn't map to unverified user\n");
  47. goto verf_fail;
  48. }
  49. lwsl_notice("Verifying %s\n", u.username);
  50. lws_snprintf(s, sizeof(s) - 1,
  51. "update users set verified=%d where username='%s';",
  52. LWSGS_VERIFIED_ACCEPTED,
  53. lws_sql_purify(esc, u.username, sizeof(esc) - 1));
  54. if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
  55. SQLITE_OK) {
  56. lwsl_err("Unable to lookup token: %s\n",
  57. sqlite3_errmsg(vhd->pdb));
  58. goto verf_fail;
  59. }
  60. lwsl_notice("deleting account\n");
  61. a.event = LWSGSE_CREATED;
  62. a.username = u.username;
  63. a.email = u.email;
  64. lws_callback_vhost_protocols(wsi, LWS_CALLBACK_GS_EVENT, &a, 0);
  65. lws_snprintf(pss->onward, sizeof(pss->onward),
  66. "%s/post-verify-ok.html", vhd->email_confirm_url);
  67. pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs;
  68. pss->delete_session.id[0] = '\0';
  69. lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
  70. /* we need to create a new, authorized session */
  71. if (lwsgs_new_session_id(vhd, &pss->login_session, u.username,
  72. pss->login_expires))
  73. goto verf_fail;
  74. lwsl_notice("Creating new session: %s, redir to %s\n",
  75. pss->login_session.id, pss->onward);
  76. return 0;
  77. verf_fail:
  78. pss->delete_session.id[0] = '\0';
  79. lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
  80. pss->login_expires = 0;
  81. lws_snprintf(pss->onward, sizeof(pss->onward), "%s/post-verify-fail.html",
  82. vhd->email_confirm_url);
  83. return 1;
  84. }
  85. /* handle forgot password confirmation links */
  86. int
  87. lwsgs_handler_forgot(struct per_vhost_data__gs *vhd, struct lws *wsi,
  88. struct per_session_data__gs *pss)
  89. {
  90. char cookie[1024], s[256], esc[50];
  91. struct lwsgs_user u;
  92. const char *a;
  93. a = lws_get_urlarg_by_name(wsi, "token=", cookie, sizeof(cookie));
  94. if (!a)
  95. goto forgot_fail;
  96. u.username[0] = '\0';
  97. lws_snprintf(s, sizeof(s) - 1,
  98. "select username,verified from users where verified=%d and "
  99. "token = '%s' and token_time != 0;",
  100. LWSGS_VERIFIED_ACCEPTED,
  101. lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
  102. if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
  103. SQLITE_OK) {
  104. lwsl_err("Unable to lookup token: %s\n",
  105. sqlite3_errmsg(vhd->pdb));
  106. goto forgot_fail;
  107. }
  108. if (!u.username[0]) {
  109. puts(s);
  110. lwsl_notice("forgot token doesn't map to verified user\n");
  111. goto forgot_fail;
  112. }
  113. /* mark user as having validated forgot flow just now */
  114. lws_snprintf(s, sizeof(s) - 1,
  115. "update users set token_time=0,last_forgot_validated=%lu "
  116. "where username='%s';",
  117. (unsigned long)lws_now_secs(),
  118. lws_sql_purify(esc, u.username, sizeof(esc) - 1));
  119. if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
  120. SQLITE_OK) {
  121. lwsl_err("Unable to lookup token: %s\n",
  122. sqlite3_errmsg(vhd->pdb));
  123. goto forgot_fail;
  124. }
  125. a = lws_get_urlarg_by_name(wsi, "good=", cookie, sizeof(cookie));
  126. if (!a)
  127. a = "broken-forget-post-good-url";
  128. lws_snprintf(pss->onward, sizeof(pss->onward),
  129. "%s/%s", vhd->email_confirm_url, a);
  130. pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs;
  131. pss->delete_session.id[0] = '\0';
  132. lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
  133. /* we need to create a new, authorized session */
  134. if (lwsgs_new_session_id(vhd, &pss->login_session,
  135. u.username,
  136. pss->login_expires))
  137. goto forgot_fail;
  138. lwsl_notice("Creating new session: %s, redir to %s\n",
  139. pss->login_session.id, pss->onward);
  140. return 0;
  141. forgot_fail:
  142. pss->delete_session.id[0] = '\0';
  143. lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
  144. pss->login_expires = 0;
  145. a = lws_get_urlarg_by_name(wsi, "bad=", cookie, sizeof(cookie));
  146. if (!a)
  147. a = "broken-forget-post-bad-url";
  148. lws_snprintf(pss->onward, sizeof(pss->onward), "%s/%s",
  149. vhd->email_confirm_url, a);
  150. return 1;
  151. }
  152. /* support dynamic username / email checking */
  153. int
  154. lwsgs_handler_check(struct per_vhost_data__gs *vhd,
  155. struct lws *wsi, struct per_session_data__gs *pss)
  156. {
  157. static const char * const colname[] = { "username", "email" };
  158. char cookie[1024], s[256], esc[50], *pc;
  159. unsigned char *p, *start, *end, buffer[LWS_PRE + 256];
  160. struct lwsgs_user u;
  161. int n;
  162. /*
  163. * either /check?email=xxx@yyy or: /check?username=xxx
  164. * returns '0' if not already registered, else '1'
  165. */
  166. u.username[0] = '\0';
  167. if (lws_hdr_copy_fragment(wsi, cookie, sizeof(cookie),
  168. WSI_TOKEN_HTTP_URI_ARGS, 0) < 0)
  169. goto reply;
  170. n = !strncmp(cookie, "email=", 6);
  171. pc = strchr(cookie, '=');
  172. if (!pc) {
  173. lwsl_notice("cookie has no =\n");
  174. goto reply;
  175. }
  176. pc++;
  177. /* admin user cannot be registered in user db */
  178. if (!strcmp(vhd->admin_user, pc)) {
  179. u.username[0] = 'a';
  180. goto reply;
  181. }
  182. lws_snprintf(s, sizeof(s) - 1,
  183. "select username, email from users where %s = '%s';",
  184. colname[n], lws_sql_purify(esc, pc, sizeof(esc) - 1));
  185. if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
  186. SQLITE_OK) {
  187. lwsl_err("Unable to lookup token: %s\n",
  188. sqlite3_errmsg(vhd->pdb));
  189. goto reply;
  190. }
  191. reply:
  192. s[0] = '0' + !!u.username[0];
  193. p = buffer + LWS_PRE;
  194. start = p;
  195. end = p + sizeof(buffer) - LWS_PRE;
  196. if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
  197. return -1;
  198. if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
  199. (unsigned char *)"text/plain", 10,
  200. &p, end))
  201. return -1;
  202. if (lws_add_http_header_content_length(wsi, 1, &p, end))
  203. return -1;
  204. if (lws_finalize_http_header(wsi, &p, end))
  205. return -1;
  206. n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
  207. if (n != (p - start)) {
  208. lwsl_err("_write returned %d from %ld\n", n, (long)(p - start));
  209. return -1;
  210. }
  211. n = lws_write(wsi, (unsigned char *)s, 1, LWS_WRITE_HTTP);
  212. if (n != 1)
  213. return -1;
  214. return 0;
  215. }
  216. /* handle forgot password confirmation links */
  217. int
  218. lwsgs_handler_change_password(struct per_vhost_data__gs *vhd, struct lws *wsi,
  219. struct per_session_data__gs *pss)
  220. {
  221. char s[256], esc[50], username[50];
  222. struct lwsgs_user u;
  223. lwsgw_hash sid;
  224. int n = 0;
  225. /* see if he's logged in */
  226. username[0] = '\0';
  227. if (!lwsgs_get_sid_from_wsi(wsi, &sid)) {
  228. u.username[0] = '\0';
  229. if (!lwsgs_lookup_session(vhd, &sid, username, sizeof(username))) {
  230. n = 1; /* yes, logged in */
  231. if (lwsgs_lookup_user(vhd, username, &u))
  232. return 1;
  233. /* did a forgot pw ? */
  234. if (u.last_forgot_validated > lws_now_secs() - 300) {
  235. n |= LWSGS_AUTH_FORGOT_FLOW;
  236. lwsl_debug("within forgot password flow\n");
  237. }
  238. }
  239. }
  240. lwsl_debug("auth value %d\n", n);
  241. /* if he just did forgot pw flow, don't need old pw */
  242. if ((n & (LWSGS_AUTH_FORGOT_FLOW | 1)) != (LWSGS_AUTH_FORGOT_FLOW | 1)) {
  243. /* otherwise user:pass must be right */
  244. lwsl_debug("checking pw\n");
  245. if (lwsgs_check_credentials(vhd,
  246. lws_spa_get_string(pss->spa, FGS_USERNAME),
  247. lws_spa_get_string(pss->spa, FGS_CURPW))) {
  248. lwsl_notice("credentials bad\n");
  249. return 1;
  250. }
  251. lwsl_debug("current pw checks out\n");
  252. strncpy(u.username, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(u.username) - 1);
  253. u.username[sizeof(u.username) - 1] = '\0';
  254. }
  255. /* does he want to delete his account? */
  256. if (lws_spa_get_length(pss->spa, FGS_DELETE)) {
  257. struct lws_gs_event_args a;
  258. lwsl_notice("deleting account\n");
  259. a.event = LWSGSE_DELETED;
  260. a.username = u.username;
  261. a.email = "";
  262. lws_callback_vhost_protocols(wsi, LWS_CALLBACK_GS_EVENT, &a, 0);
  263. lws_snprintf(s, sizeof(s) - 1,
  264. "delete from users where username='%s';"
  265. "delete from sessions where username='%s';",
  266. lws_sql_purify(esc, u.username, sizeof(esc) - 1),
  267. lws_sql_purify(esc, u.username, sizeof(esc) - 1));
  268. goto sql;
  269. }
  270. if (lwsgs_hash_password(vhd, lws_spa_get_string(pss->spa, FGS_PASSWORD), &u))
  271. return 1;
  272. lwsl_notice("updating password hash\n");
  273. lws_snprintf(s, sizeof(s) - 1,
  274. "update users set pwhash='%s', pwsalt='%s', "
  275. "last_forgot_validated=0 where username='%s';",
  276. u.pwhash.id, u.pwsalt.id,
  277. lws_sql_purify(esc, u.username, sizeof(esc) - 1));
  278. sql:
  279. if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
  280. lwsl_err("Unable to update pw hash: %s\n",
  281. sqlite3_errmsg(vhd->pdb));
  282. return 1;
  283. }
  284. return 0;
  285. }
  286. int
  287. lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd,
  288. struct lws *wsi,
  289. struct per_session_data__gs *pss)
  290. {
  291. char s[LWSGS_EMAIL_CONTENT_SIZE];
  292. unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
  293. char esc[50], esc1[50], esc2[50], esc3[50], esc4[50];
  294. struct lwsgs_user u;
  295. lwsgw_hash hash;
  296. unsigned char sid_rand[20];
  297. int n;
  298. lwsl_notice("FORGOT %s %s\n",
  299. lws_spa_get_string(pss->spa, FGS_USERNAME),
  300. lws_spa_get_string(pss->spa, FGS_EMAIL));
  301. if (!lws_spa_get_string(pss->spa, FGS_USERNAME) &&
  302. !lws_spa_get_string(pss->spa, FGS_EMAIL)) {
  303. lwsl_err("Form must provide either "
  304. "username or email\n");
  305. return -1;
  306. }
  307. if (!lws_spa_get_string(pss->spa, FGS_FORGOT_GOOD) ||
  308. !lws_spa_get_string(pss->spa, FGS_FORGOT_BAD) ||
  309. !lws_spa_get_string(pss->spa, FGS_FORGOT_POST_GOOD) ||
  310. !lws_spa_get_string(pss->spa, FGS_FORGOT_POST_BAD)) {
  311. lwsl_err("Form must provide reg-good "
  312. "and reg-bad (and post-*)"
  313. "targets\n");
  314. return -1;
  315. }
  316. u.username[0] = '\0';
  317. if (lws_spa_get_string(pss->spa, FGS_USERNAME))
  318. lws_snprintf(s, sizeof(s) - 1,
  319. "select username,email "
  320. "from users where username = '%s';",
  321. lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME),
  322. sizeof(esc) - 1));
  323. else
  324. lws_snprintf(s, sizeof(s) - 1,
  325. "select username,email "
  326. "from users where email = '%s';",
  327. lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc) - 1));
  328. if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
  329. SQLITE_OK) {
  330. lwsl_err("Unable to lookup token: %s\n",
  331. sqlite3_errmsg(vhd->pdb));
  332. return 1;
  333. }
  334. if (!u.username[0]) {
  335. lwsl_err("No match found %s\n", s);
  336. return 1;
  337. }
  338. lws_get_peer_simple(wsi, pss->ip, sizeof(pss->ip));
  339. if (lws_get_random(vhd->context, sid_rand,
  340. sizeof(sid_rand)) !=
  341. sizeof(sid_rand)) {
  342. lwsl_err("Problem getting random for token\n");
  343. return 1;
  344. }
  345. sha1_to_lwsgw_hash(sid_rand, &hash);
  346. n = lws_snprintf(s, sizeof(s),
  347. "From: Forgot Password Assistant Noreply <%s>\n"
  348. "To: %s <%s>\n"
  349. "Subject: Password reset request\n"
  350. "\n"
  351. "Hello, %s\n\n"
  352. "We received a password reset request from IP %s for this email,\n"
  353. "to confirm you want to do that, please click the link below.\n\n",
  354. lws_sql_purify(esc, vhd->email.email_from, sizeof(esc) - 1),
  355. lws_sql_purify(esc1, u.username, sizeof(esc1) - 1),
  356. lws_sql_purify(esc2, u.email, sizeof(esc2) - 1),
  357. lws_sql_purify(esc3, u.username, sizeof(esc3) - 1),
  358. lws_sql_purify(esc4, pss->ip, sizeof(esc4) - 1));
  359. lws_snprintf(s + n, sizeof(s) -n,
  360. "%s/lwsgs-forgot?token=%s"
  361. "&good=%s"
  362. "&bad=%s\n\n"
  363. "If this request is unexpected, please ignore it and\n"
  364. "no further action will be taken.\n\n"
  365. "If you have any questions or concerns about this\n"
  366. "automated email, you can contact a real person at\n"
  367. "%s.\n"
  368. "\n.\n",
  369. vhd->email_confirm_url, hash.id,
  370. lws_urlencode(esc1,
  371. lws_spa_get_string(pss->spa, FGS_FORGOT_POST_GOOD),
  372. sizeof(esc1) - 1),
  373. lws_urlencode(esc3,
  374. lws_spa_get_string(pss->spa, FGS_FORGOT_POST_BAD),
  375. sizeof(esc3) - 1),
  376. vhd->email_contact_person);
  377. lws_snprintf((char *)buffer, sizeof(buffer) - 1,
  378. "insert into email(username, content)"
  379. " values ('%s', '%s');",
  380. lws_sql_purify(esc, u.username, sizeof(esc) - 1), s);
  381. if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL,
  382. NULL, NULL) != SQLITE_OK) {
  383. lwsl_err("Unable to insert email: %s\n",
  384. sqlite3_errmsg(vhd->pdb));
  385. return 1;
  386. }
  387. lws_snprintf(s, sizeof(s) - 1,
  388. "update users set token='%s',token_time='%ld' where username='%s';",
  389. hash.id, (long)lws_now_secs(),
  390. lws_sql_purify(esc, u.username, sizeof(esc) - 1));
  391. if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) !=
  392. SQLITE_OK) {
  393. lwsl_err("Unable to set token: %s\n",
  394. sqlite3_errmsg(vhd->pdb));
  395. return 1;
  396. }
  397. return 0;
  398. }
  399. int
  400. lwsgs_handler_register_form(struct per_vhost_data__gs *vhd,
  401. struct lws *wsi,
  402. struct per_session_data__gs *pss)
  403. {
  404. unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
  405. char esc[50], esc1[50], esc2[50], esc3[50], esc4[50];
  406. char s[LWSGS_EMAIL_CONTENT_SIZE];
  407. unsigned char sid_rand[20];
  408. struct lwsgs_user u;
  409. lwsgw_hash hash;
  410. lwsl_notice("REGISTER %s %s %s\n",
  411. lws_spa_get_string(pss->spa, FGS_USERNAME),
  412. lws_spa_get_string(pss->spa, FGS_PASSWORD),
  413. lws_spa_get_string(pss->spa, FGS_EMAIL));
  414. if (lwsgs_get_sid_from_wsi(wsi,
  415. &pss->login_session))
  416. return 1;
  417. lws_get_peer_simple(wsi, pss->ip, sizeof(pss->ip));
  418. lwsl_notice("IP=%s\n", pss->ip);
  419. if (!lws_spa_get_string(pss->spa, FGS_REG_GOOD) ||
  420. !lws_spa_get_string(pss->spa, FGS_REG_BAD)) {
  421. lwsl_info("Form must provide reg-good and reg-bad targets\n");
  422. return -1;
  423. }
  424. /* admin user cannot be registered in user db */
  425. if (!strcmp(vhd->admin_user,
  426. lws_spa_get_string(pss->spa, FGS_USERNAME)))
  427. return 1;
  428. if (!lwsgs_lookup_user(vhd,
  429. lws_spa_get_string(pss->spa, FGS_USERNAME), &u)) {
  430. lwsl_notice("user %s already registered\n",
  431. lws_spa_get_string(pss->spa, FGS_USERNAME));
  432. return 1;
  433. }
  434. u.username[0] = '\0';
  435. lws_snprintf(s, sizeof(s) - 1, "select username, email from users where email = '%s';",
  436. lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_EMAIL),
  437. sizeof(esc) - 1));
  438. if (sqlite3_exec(vhd->pdb, s,
  439. lwsgs_lookup_callback_user, &u, NULL) != SQLITE_OK) {
  440. lwsl_err("Unable to lookup token: %s\n",
  441. sqlite3_errmsg(vhd->pdb));
  442. return 1;
  443. }
  444. if (u.username[0]) {
  445. lwsl_notice("email %s already in use\n",
  446. lws_spa_get_string(pss->spa, FGS_USERNAME));
  447. return 1;
  448. }
  449. if (lwsgs_hash_password(vhd, lws_spa_get_string(pss->spa, FGS_PASSWORD),
  450. &u)) {
  451. lwsl_err("Password hash failed\n");
  452. return 1;
  453. }
  454. if (lws_get_random(vhd->context, sid_rand, sizeof(sid_rand)) !=
  455. sizeof(sid_rand)) {
  456. lwsl_err("Problem getting random for token\n");
  457. return 1;
  458. }
  459. sha1_to_lwsgw_hash(sid_rand, &hash);
  460. lws_snprintf((char *)buffer, sizeof(buffer) - 1,
  461. "insert into users(username,"
  462. " creation_time, ip, email, verified,"
  463. " pwhash, pwsalt, token, last_forgot_validated)"
  464. " values ('%s', %lu, '%s', '%s', 0,"
  465. " '%s', '%s', '%s', 0);",
  466. lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc) - 1),
  467. (unsigned long)lws_now_secs(),
  468. lws_sql_purify(esc1, pss->ip, sizeof(esc1) - 1),
  469. lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
  470. u.pwhash.id, u.pwsalt.id, hash.id);
  471. if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL, NULL, NULL) != SQLITE_OK) {
  472. lwsl_err("Unable to insert user: %s\n",
  473. sqlite3_errmsg(vhd->pdb));
  474. return 1;
  475. }
  476. lws_snprintf(s, sizeof(s),
  477. "From: Noreply <%s>\n"
  478. "To: %s <%s>\n"
  479. "Subject: Registration verification\n"
  480. "\n"
  481. "Hello, %s\n\n"
  482. "We received a registration from IP %s using this email,\n"
  483. "to confirm it is legitimate, please click the link below.\n\n"
  484. "%s/lwsgs-confirm?token=%s\n\n"
  485. "If this request is unexpected, please ignore it and\n"
  486. "no further action will be taken.\n\n"
  487. "If you have any questions or concerns about this\n"
  488. "automated email, you can contact a real person at\n"
  489. "%s.\n"
  490. "\n.\n",
  491. lws_sql_purify(esc, vhd->email.email_from, sizeof(esc) - 1),
  492. lws_sql_purify(esc1, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc1) - 1),
  493. lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
  494. lws_sql_purify(esc3, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc3) - 1),
  495. lws_sql_purify(esc4, pss->ip, sizeof(esc4) - 1),
  496. vhd->email_confirm_url, hash.id,
  497. vhd->email_contact_person);
  498. lws_snprintf((char *)buffer, sizeof(buffer) - 1,
  499. "insert into email(username, content) values ('%s', '%s');",
  500. lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME),
  501. sizeof(esc) - 1), s);
  502. if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL, NULL, NULL) != SQLITE_OK) {
  503. lwsl_err("Unable to insert email: %s\n",
  504. sqlite3_errmsg(vhd->pdb));
  505. return 1;
  506. }
  507. return 0;
  508. }