From a18d862c56f16853a82658eaf76d67da545fa693 Mon Sep 17 00:00:00 2001 From: Adam Rambousek Date: Thu, 31 May 2018 10:29:42 +0200 Subject: [PATCH 1/7] create mail transport --- website/lexonomy.js | 1 + 1 file changed, 1 insertion(+) diff --git a/website/lexonomy.js b/website/lexonomy.js index d1e8e765..18f98fb8 100644 --- a/website/lexonomy.js +++ b/website/lexonomy.js @@ -20,6 +20,7 @@ const querystring=require("querystring"); const libxslt=require("libxslt"); //https://www.npmjs.com/package/libxslt const sqlite3 = require('sqlite3').verbose(); //https://www.npmjs.com/package/sqlite3 const nodemailer = require('nodemailer'); +ops.mailtransporter = nodemailer.createTransport(siteconfig.mailconfig); const PORT=process.env.PORT||siteconfig.port||80; //Do this for each request: From a77e23cfe7692b8decc2cebd5ab78504f1476534 Mon Sep 17 00:00:00 2001 From: Adam Rambousek Date: Thu, 31 May 2018 10:38:26 +0200 Subject: [PATCH 2/7] new versions --- website/package-lock.json | 6 +++--- website/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index c74d4842..d4f20959 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -428,9 +428,9 @@ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, "nodemailer": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.6.4.tgz", - "integrity": "sha512-SD4uuX7NMzZ5f5m1XHDd13J4UC3SmdJk8DsmU1g6Nrs5h3x9LcXr6EBPZIqXRJ3LrF7RdklzGhZRF/TuylTcLg==" + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.6.5.tgz", + "integrity": "sha512-+bt+BgmnOXDz1uIaWXfXuTESth8UHkhtu7+X8+X2W+CHAn0AuuCyCk854qnathYQLWEC2jkpx7/pkVHcfmLKDw==" }, "nopt": { "version": "2.1.2", diff --git a/website/package.json b/website/package.json index 1073b53e..a10167a5 100644 --- a/website/package.json +++ b/website/package.json @@ -7,7 +7,7 @@ "libxslt": "^0.7.0", "markdown": "^0.5.0", "multer": "^1.3.0", - "nodemailer": "^4.6.4", + "nodemailer": "^4.6.5", "sha1": "^1.1.1", "sqlite3": "^3.1.13", "xmldom": "^0.1.27" From 590eaccfe1ce48b666194829facb7fbc97f442fd Mon Sep 17 00:00:00 2001 From: Adam Rambousek Date: Thu, 31 May 2018 11:09:25 +0200 Subject: [PATCH 3/7] rename localized error --- website/libs/screenful/screenful-forgotpwd.js | 2 +- website/libs/screenful/screenful-loc-cs.js | 2 +- website/libs/screenful/screenful-loc-en.js | 2 +- website/libs/screenful/screenful-loc-ga.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/website/libs/screenful/screenful-forgotpwd.js b/website/libs/screenful/screenful-forgotpwd.js index 5d91625c..f9fbc374 100644 --- a/website/libs/screenful/screenful-forgotpwd.js +++ b/website/libs/screenful/screenful-forgotpwd.js @@ -7,7 +7,7 @@ Screenful.ForgotPwd={ $("#middlebox .one").append("
"); $("#middlebox .two").append("
"+Screenful.Loc.tokenSent+"
"); $("#middlebox .two").append("
"); - $("#middlebox").append(""); + $("#middlebox").append(""); $("#middlebox div.field.email input").focus(); $("#middlebox").on("submit", function(e){ diff --git a/website/libs/screenful/screenful-loc-cs.js b/website/libs/screenful/screenful-loc-cs.js index 4c0004e7..f8afb375 100755 --- a/website/libs/screenful/screenful-loc-cs.js +++ b/website/libs/screenful/screenful-loc-cs.js @@ -59,10 +59,10 @@ Screenful.Loc={ invalidSourceCode: "Neplatný zdrojový kód", unsavedConfirm: "Más neuložené změny. Opravdu o ně chceš přijít?", doItLater: "Udělej to jindy", + badEmailError: "Nesprávná e-mailová adresa.", forgotPwdEmail: "Zapomněli-li jste svoje heslo, zadejte tady svoji e-mailovou adresu a my vám pošleme instrukce, jak si získat nové heslo.", recoverPwd: "Chci nové heslo", - forgotPwdError: "Nesprávná e-mailová adresa.", tokenSent: "Poslali jsme vám instrukce, jak si získat nové heslo.", recoverPwdMsg: "Nyní si můžete změnit heslo.", changePwdMsg: "Tady si můžete změnit heslo.", diff --git a/website/libs/screenful/screenful-loc-en.js b/website/libs/screenful/screenful-loc-en.js index fd0fa57e..8ce983c3 100644 --- a/website/libs/screenful/screenful-loc-en.js +++ b/website/libs/screenful/screenful-loc-en.js @@ -59,10 +59,10 @@ Screenful.Loc={ invalidSourceCode: "Invalid source code", unsavedConfirm: "You have unsaved changes. Are you sure you want to lose them?", doItLater: "Do it later", + badEmailError: "Incorrect e-mail address.", forgotPwdEmail: "If you have forgotten your password, enter your e-mail address and we will send you instructions on how to create a new one.", recoverPwd: "Get a new password", - forgotPwdError: "Incorrect e-mail address.", tokenSent: "We have sent you an e-mail with instructions on how to reset your password.", recoverPwdMsg: "You can change your password now.", changePwdMsg: "You can change your password here.", diff --git a/website/libs/screenful/screenful-loc-ga.js b/website/libs/screenful/screenful-loc-ga.js index dfa1b1a6..728c5340 100755 --- a/website/libs/screenful/screenful-loc-ga.js +++ b/website/libs/screenful/screenful-loc-ga.js @@ -59,10 +59,10 @@ Screenful.Loc={ invalidSourceCode: "Cód foinseach neamhbhailí", unsavedConfirm: "Tá athruithe déanta agat nach bhfuil sábháilte go fóill. An cuma leat go gcaillfear iad?", doItLater: "Déan níos déanaí é", + badEmailError: "Seoladh ríomhphoist mícheart.", forgotPwdEmail: "Má tá do phasfhocal dearmadta agat, cuir do sheoladh ríomhphoist isteach anseo. Cuirfidh muidne treoracha chugat maidir leis an dóigh chun do phasfhocal a athrú.", recoverPwd: "Faigh pasfhocal nua", - forgotPwdError: "Seoladh ríomhphoist mícheart.", tokenSent: "Tá treoracha seolta againn chugat maidir leis an dóigh chun do phasfhocal a athrú.", recoverPwdMsg: "Is féidir leat do phasfhocal a athrú anois.", changePwdMsg: "Is féidir leat do phasfhocal a athrú anseo.", From 150f84134733f7e4c4dcfa50bf70c9ac1cc7f3ed Mon Sep 17 00:00:00 2001 From: Adam Rambousek Date: Sat, 2 Jun 2018 17:42:29 +0200 Subject: [PATCH 4/7] create new account --- data/lexonomy.sqlite.template | Bin 172032 -> 172032 bytes website/adminscripts/updates.js | 6 ++ website/lexonomy.js | 24 +++++++- .../screenful/screenful-createaccount.css | 19 +++++++ .../libs/screenful/screenful-createaccount.js | 47 ++++++++++++++++ website/libs/screenful/screenful-loc-cs.js | 7 +++ website/libs/screenful/screenful-loc-en.js | 7 +++ website/libs/screenful/screenful-loc-ga.js | 7 +++ website/libs/screenful/screenful-signup.css | 18 ++++-- website/libs/screenful/screenful-signup.js | 34 +++++++++++- website/ops.js | 52 +++++++++++++++++- website/views/createaccount.ejs | 35 ++++++++++++ website/views/signup.ejs | 3 +- 13 files changed, 246 insertions(+), 13 deletions(-) create mode 100644 website/libs/screenful/screenful-createaccount.css create mode 100644 website/libs/screenful/screenful-createaccount.js create mode 100644 website/views/createaccount.ejs diff --git a/data/lexonomy.sqlite.template b/data/lexonomy.sqlite.template index 2afa38f4b98ab405e4a5d1144e2825a535ec1681..55e3597d539259ac51a1fc3ca612a2cbc7787723 100644 GIT binary patch delta 157 zcmZoTz}0YoYl5`kbOr_nEg%*KVi_Pdn5bjSGo3+CVm!uZOm*i)s<`tuH`J97X9Yb6dLL8lZToquFlS{et nHyd%EJF@8jlfY)C2doZ^($hH<808t|+cgvzw`(Xc-KYluk)$tJ delta 1209 zcmY*XU1%It6uxKf%>K^qW=*T4&Ce~hAse&l?CfqfyK0mDNp!WgTa#368I##$OvY?> z?98mtw8)UTlXv+3@##s+D+7(Xfkp1Qb&|sM4kJ7^09fudihI}4XeS0%br!<`_1Q7 zkC~FEmQmo7z)D~-a3N3%JRNBD|LMQxU+_Qc@9^FAec>~FBfc>E7rVi}%8G2Kchmcd zx65dF=wmO<+$m%?pSsxjtFyyS)-PjcbV6j zDpO#38IHm9CcQzg(aG27m*@%lIGv!I=pg{JaSz^4-J)vL6qThK;5YaTmS74p za3A^=eG31eztOkG+*Wioed8J!tux0A<>wIe+uUb!#^$um582#hbJ*Cp*xIlUhap$d zM<<3KQ6*_|cu>-G>L5;1wa68?w+f^YKSd!CY3^U2XKPQof#|)kblo!h~u{KdfxBd7KTC<5JIAbyM#9^GLY9C*PW+&Y96g_{G zs)=qmFcXo@-;f?V@HIoX}<(G284Skwhxior*_= zq_HxaF-GptwXG#!jQ3~G{%074+4p>WBo*fbw0w%5KLSSjnTL%oz0S-SFmZz6BLc+D zC|~P+16&kbu;Z0>a67*L|3*ER4D(5=jaW1l?G~y$9yi3<`;C>VmtNcvEZ&K|bjxnh zydyje+S;SO+@m)3sH=O_
"); + if (Screenful.CreateAccount.tokenValid) { + $("#middlebox .one").append("
"+Screenful.Loc.setPwdMsg+"
"); + $("#middlebox .one").append("
"+Screenful.Loc.newPassword+"
"); + $("#middlebox .one").append("
"); + $("#middlebox .one").append(""); + $("#middlebox .two").append("
"+Screenful.Loc.accountCreated+"
"); + $("#middlebox .two").append("
"); + } else { + $("#middlebox .one").append("
"+Screenful.Loc.invalidSignupToken+"
"); + $("#middlebox .one").append("
"); + } + + $("#middlebox div.field.password input").focus(); + + $("#middlebox").on("submit", function(e){ + var password=$("#middlebox div.field.password input").val(); + if(password=="") { $("#middlebox .error").html(Screenful.Loc.passwordEmpty).show(); return false; } + if(password.length<6) { $("#middlebox .error").html(Screenful.Loc.passwordShort).show(); return false; } + if($.trim(password)!=password) { $("#middlebox .error").html(Screenful.Loc.passwordWhitespace).show(); return false; } + Screenful.CreateAccount.go(password); + return false; + }); + + $("#middlebox button.return").on("click", function(e){ + window.location=Screenful.CreateAccount.returnUrl; + return false; + }); + }, + + go: function(password){ + $.ajax({url: Screenful.CreateAccount.actionUrl, dataType: "json", method: "POST", data: {password: password, token: Screenful.CreateAccount.token}}).done(function(data){ + if(data.success) { + $("#middlebox .one").hide(); + $("#middlebox .two").show() + } else { + $("#middlebox .error").html(Screenful.Loc.signupAccountExists).show(); + } + }); + }, + + +}; +$(window).ready(Screenful.CreateAccount.start); diff --git a/website/libs/screenful/screenful-loc-cs.js b/website/libs/screenful/screenful-loc-cs.js index f8afb375..00547791 100755 --- a/website/libs/screenful/screenful-loc-cs.js +++ b/website/libs/screenful/screenful-loc-cs.js @@ -68,4 +68,11 @@ Screenful.Loc={ changePwdMsg: "Tady si můžete změnit heslo.", invalidToken: "Tento odkaz je neplatný. Možná už vypršel, nebo byl už použit.", + signupInfoEmail: "To get a new account, enter your e-mail address and we will send you instructions.", + signupButton: "Create new account", + signupTokenSent: "We have sent you an e-mail with instructions on how to reset your password.", + invalidSignupToken: "This signup link is invalid. It may have expired or has been used before.", + setPwdMsg: "Please, set your password now.", + accountCreated: "We have created your account. You may now log-in with your e-mail and password.", + signupAccountExists: "You are trying to create account for e-mail that is already existing. Did you forget your password?", }; diff --git a/website/libs/screenful/screenful-loc-en.js b/website/libs/screenful/screenful-loc-en.js index 8ce983c3..70f0353b 100644 --- a/website/libs/screenful/screenful-loc-en.js +++ b/website/libs/screenful/screenful-loc-en.js @@ -68,4 +68,11 @@ Screenful.Loc={ changePwdMsg: "You can change your password here.", invalidToken: "This password reset link is invalid. It may have expired or has been used before.", + signupInfoEmail: "To get a new account, enter your e-mail address and we will send you instructions.", + signupButton: "Create new account", + signupTokenSent: "We have sent you an e-mail with instructions on how to reset your password.", + invalidSignupToken: "This signup link is invalid. It may have expired or has been used before.", + setPwdMsg: "Please, set your password now.", + accountCreated: "We have created your account. You may now log-in with your e-mail and password.", + signupAccountExists: "You are trying to create account for e-mail that is already existing. Did you forget your password?", }; diff --git a/website/libs/screenful/screenful-loc-ga.js b/website/libs/screenful/screenful-loc-ga.js index 728c5340..5a066330 100755 --- a/website/libs/screenful/screenful-loc-ga.js +++ b/website/libs/screenful/screenful-loc-ga.js @@ -68,4 +68,11 @@ Screenful.Loc={ changePwdMsg: "Is féidir leat do phasfhocal a athrú anseo.", invalidToken: "Níl an nasc seo bailí. Seans go bhfuil sé imithe in éag, nó b'fhéidir gur baineadh úsáid as cheana.", + signupInfoEmail: "To get a new account, enter your e-mail address and we will send you instructions.", + signupButton: "Create new account", + signupTokenSent: "We have sent you an e-mail with instructions on how to reset your password.", + invalidSignupToken: "This signup link is invalid. It may have expired or has been used before.", + setPwdMsg: "Please, set your password now.", + accountCreated: "We have created your account. You may now log-in with your e-mail and password.", + signupAccountExists: "You are trying to create account for e-mail that is already existing. Did you forget your password?", }; diff --git a/website/libs/screenful/screenful-signup.css b/website/libs/screenful/screenful-signup.css index 15d29622..7604433b 100644 --- a/website/libs/screenful/screenful-signup.css +++ b/website/libs/screenful/screenful-signup.css @@ -1,6 +1,16 @@ #middlebox {max-width: 600px; padding: 40px 30px; min-height: 100px; margin: 75px auto 50px auto; border: 1px solid rgb(38, 122, 181); background-color: #ffffff; border-radius: 4px; box-shadow: 0px 0px 4px #666666; } -#middlebox div.message {text-align: center; margin: 50px 0px 0px 0px;} -#middlebox div.url {text-align: center; margin: 10px 0px 50px 0px;} -#middlebox div.url a {text-decoration: none; color: #004f9b;} -#middlebox div.url a:hover {color: #006ed7;} +#middlebox div.field {margin-top: 30px;} +#middlebox div.field:first-child {margin-top: 0px;} +#middlebox div.field div.label {font-weight: bold; margin: 0px 0px 5px 0px; color: #333333;} +#middlebox div.field input.textbox {box-sizing: border-box; width: 100%; margin: 0px 0px 0px 0px; font: inherit; border-width: 0px; border-radius: 4px; background-color: #ffffff; box-shadow: inset 0px 0px 2px #666666; padding: 9px 8px; min-height: 1.3em; display: inline-block; vertical-align: middle;} +#middlebox div.field input.button {box-sizing: border-box; margin: 0px 0px 0px 0px; font: inherit; border-width: 0px; border-radius: 4px; background-color: #ffffff; box-shadow: 0px 0px 2px #666666; padding: 9px 30px; min-height: 1.3em; display: inline-block; vertical-align: middle; color: #267ab5; cursor: pointer;} +#middlebox div.field input.button:hover {color: #4698d1;} +#middlebox div.field button {box-sizing: border-box; margin: 0px 0px 0px 0px; font: inherit; border-width: 0px; border-radius: 4px; background-color: #ffffff; box-shadow: 0px 0px 2px #666666; padding: 9px 30px; min-height: 1.3em; display: inline-block; vertical-align: middle; color: #267ab5; cursor: pointer;} +#middlebox div.field button:hover {color: #4698d1;} + +#middlebox div.field.submit {text-align: center;} +#middlebox div.field.submit input.button {font-weight: bold;} +#middlebox div.field.submit button {font-weight: bold;} + +#middlebox div.error {background-color: #ffcdcc; color: #99004d; font-weight: bold; text-align: center; padding: 40px; margin: 30px -30px -40px -30px; text-shadow: 1px 1px 0px #eeeeee;} diff --git a/website/libs/screenful/screenful-signup.js b/website/libs/screenful/screenful-signup.js index 4266e713..83c28543 100644 --- a/website/libs/screenful/screenful-signup.js +++ b/website/libs/screenful/screenful-signup.js @@ -1,9 +1,37 @@ Screenful.Signup={ start: function(){ Screenful.createEnvelope(true); - $("#envelope").html("
"); - $("#middlebox").append("
"+Screenful.Loc.signupEmail+"
"); - $("#middlebox").append(""); + $("#envelope").html("
"); + $("#middlebox .one").append("
"+Screenful.Loc.signupInfoEmail+"
"); + $("#middlebox .one").append(""); + $("#middlebox .one").append("
"); + $("#middlebox .two").append("
"+Screenful.Loc.signupTokenSent+"
"); + $("#middlebox .two").append("
"); + $("#middlebox").append(""); + + $("#middlebox div.field.email input").focus(); + $("#middlebox").on("submit", function(e){ + var email=$("#middlebox div.field.email input").val(); + if (email!="") Screenful.Signup.sendToken(email); + return false; + }); + + $("#middlebox button.return").on("click", function(e){ + window.location=Screenful.Signup.returnUrl; + return false; + }); + }, + + sendToken: function(email){ + $("#middlebox div.error").hide(); + $.ajax({url: Screenful.Signup.actionUrl, dataType: "json", method: "POST", data: {email: email}}).done(function(data){ + if(data.success) { + $("#middlebox .one").hide(); + $("#middlebox .two").show(); + } else { + $("#middlebox div.error").fadeIn(); + } + }); }, }; $(window).ready(Screenful.Signup.start); diff --git a/website/ops.js b/website/ops.js index 75f172ae..ac412a8d 100644 --- a/website/ops.js +++ b/website/ops.js @@ -902,6 +902,31 @@ module.exports={ callnext(true); }); }, + sendSignupToken: function(email, remoteip, callnext){ + var db=new sqlite3.Database(path.join(module.exports.siteconfig.dataDir, "lexonomy.sqlite"), sqlite3.OPEN_READWRITE); + db.get("select email from users where email=$email", {$email: email}, function(err, row){ + if (row==undefined) { + var expireDate = (new Date()); expireDate.setHours(expireDate.getHours()+48); + expireDate = expireDate.toISOString(); + var token = sha1(sha1(Math.random())); + var tokenurl = module.exports.siteconfig.baseUrl + 'createaccount/' + token; + var mailSubject="Lexonomy signup"; + var mailText = `Dear Lexonomy user,\n\n`; + mailText+=`Somebody (hopefully you, from the address ${remoteip}) requested to create a new account for Lexonomy. Please follow the link below to create your account:\n\n` + mailText+=`${tokenurl}\n\n`; + mailText+=`For security reasons this link is only valid for two days (until ${expireDate}). If you did not request an account, you can safely ignore this message. \n\n`; + mailText+=`Yours,\nThe Lexonomy team`; + db.run("insert into register_tokens (email, requestAddress, token, expiration) values ($email, $remoteip, $token, $expire)", {$email: email, $expire: expireDate, $remoteip: remoteip, $token: token}, function(err, row){ + module.exports.mailtransporter.sendMail({from: module.exports.siteconfig.admins[0], to: email, subject: mailSubject, text: mailText}, (err, info) => {}); + db.close(); + callnext(true); + }); + } else { + db.close(); + callnext(false); + } + }); + }, sendToken: function(email, remoteip, callnext){ var db=new sqlite3.Database(path.join(module.exports.siteconfig.dataDir, "lexonomy.sqlite"), sqlite3.OPEN_READWRITE); db.get("select email from users where email=$email", {$email: email}, function(err, row){ @@ -927,13 +952,34 @@ module.exports={ } }); }, - verifyToken: function(token, callnext){ + verifyToken: function(token, type, callnext){ var db=new sqlite3.Database(path.join(module.exports.siteconfig.dataDir, "lexonomy.sqlite"), sqlite3.OPEN_READWRITE); - db.get("select * from recovery_tokens where token=$token and expiration>=datetime('now') and usedDate is null", {$token: token}, function(err, row){ + db.get("select * from "+type+"_tokens where token=$token and expiration>=datetime('now') and usedDate is null", {$token: token}, function(err, row){ db.close(); if(!row) callnext(false); else callnext(true); }); }, + createAccount: function(token, password, remoteip, callnext){ + var db=new sqlite3.Database(path.join(module.exports.siteconfig.dataDir, "lexonomy.sqlite"), sqlite3.OPEN_READWRITE); + db.get("select * from register_tokens where token=$token and expiration>=datetime('now') and usedDate is null", {$token: token}, function(err, row){ + if (row) { + var email = row.email; + db.get("select * from users where email=$email", {$email: email}, function(err, row){ + if (row==undefined) { + var hash = sha1(password); + db.run("insert into users (email,passwordHash) values ($email,$hash)", {$hash: hash, $email: email}, function(err, row){ + db.run("update register_tokens set usedDate=datetime('now'), usedAddress=$remoteip where token=$token", {$remoteip: remoteip, $token: token}, function(err, row){ + db.close(); + callnext(true); + }); + }); + } else { + callnext(false); + } + }); + } + }); + }, resetPwd: function(token, password, remoteip, callnext){ var db=new sqlite3.Database(path.join(module.exports.siteconfig.dataDir, "lexonomy.sqlite"), sqlite3.OPEN_READWRITE); db.get("select * from recovery_tokens where token=$token and expiration>=datetime('now') and usedDate is null", {$token: token}, function(err, row){ @@ -1248,4 +1294,4 @@ function getDoctype(xml){ return ret; } -const prohibitedDictIDs=["login", "logout", "make", "signup", "forgotpwd", "changepwd", "users", "dicts", "oneclick", "recoverpwd"]; +const prohibitedDictIDs=["login", "logout", "make", "signup", "forgotpwd", "changepwd", "users", "dicts", "oneclick", "recoverpwd","createaccount"]; diff --git a/website/views/createaccount.ejs b/website/views/createaccount.ejs new file mode 100644 index 00000000..56f304b0 --- /dev/null +++ b/website/views/createaccount.ejs @@ -0,0 +1,35 @@ + + + + + + Create your account + + + + + + + + + + + + + + + + + + diff --git a/website/views/signup.ejs b/website/views/signup.ejs index 81e4dd15..fca2f693 100644 --- a/website/views/signup.ejs +++ b/website/views/signup.ejs @@ -20,7 +20,8 @@ From 542cb15b9b7291badd6c99fa0e01b7c3f9476ea9 Mon Sep 17 00:00:00 2001 From: Adam Rambousek Date: Tue, 12 Jun 2018 13:08:47 +0200 Subject: [PATCH 5/7] add SketchEnginge integration to db schema --- data/lexonomy.sqlite.template | Bin 172032 -> 172032 bytes website/adminscripts/updates.js | 12 +++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/data/lexonomy.sqlite.template b/data/lexonomy.sqlite.template index 55e3597d539259ac51a1fc3ca612a2cbc7787723..5fa56138320b50798cea4eebc0adc10ee382c148 100644 GIT binary patch delta 141 zcmZoTz}0YoYl5`kOa=x9Eg%*KVi_Pdny6zeK9fOD mH#czcvoJbNp1`+}h5rXb&%}ux&1d=B&+;>FKg-W#JOKc%q9^_U delta 101 zcmZoTz}0YoYl5`kbOr_nEg%*KVi_Pdn5bhcKAk~N Date: Tue, 12 Jun 2018 15:44:31 +0200 Subject: [PATCH 6/7] Sketch engine login, using JWT --- website/furniture/public.css | 5 ++ website/lexonomy.js | 37 ++++++++++++- website/ops.js | 47 ++++++++++++++++- website/package-lock.json | 91 ++++++++++++++++++++++++++++++++ website/package.json | 1 + website/siteconfig.json.template | 2 + website/views/home.ejs | 16 ++++++ 7 files changed, 196 insertions(+), 3 deletions(-) diff --git a/website/furniture/public.css b/website/furniture/public.css index 5e0bbd1a..bfbc2d81 100644 --- a/website/furniture/public.css +++ b/website/furniture/public.css @@ -136,6 +136,11 @@ div.usertop a:hover {color: #2c7fba; } div.usertop > div.title {font-size: 1.5rem; padding-top: 10px;} div.usertop > div.subtitle {margin-top: 10px; color: #666666;} +div.skelogin a {text-decoration: none; color: #09587e;} +div.skelogin a:hover {color: #2c7fba; } +div.skelogin {font-weight: bold; text-align: center; padding: 10px; margin: 20px 0px 0px 0px; border-radius: 4px; border: 1px solid #279FD2;} +div.skelogin img {vertical-align: middle;} + div.field {margin-top: 10px;} div.field:first-child {margin-top: 0px;} div.field div.label {font-weight: bold; margin: 0px 0px 5px 0px; color: #333333;} diff --git a/website/lexonomy.js b/website/lexonomy.js index b91158b4..6f32b697 100644 --- a/website/lexonomy.js +++ b/website/lexonomy.js @@ -22,6 +22,7 @@ const sqlite3 = require('sqlite3').verbose(); //https://www.npmjs.com/package/sq const nodemailer = require('nodemailer'); ops.mailtransporter = nodemailer.createTransport(siteconfig.mailconfig); const PORT=process.env.PORT||siteconfig.port||80; +const jwt = require("jsonwebtoken"); //Do this for each request: app.use(function (req, res, next) { @@ -60,7 +61,12 @@ app.get(siteconfig.rootPath+":dictID/en/", function(req, res){ res.redirect("/"+ app.get(siteconfig.rootPath, function(req, res){ ops.verifyLogin(req.cookies.email, req.cookies.sessionkey, function(user){ ops.getDictsByUser(user.email, function(dicts){ - res.render("home.ejs", {siteconfig: siteconfig, user: user, dicts: dicts}); + var error = null; + if (req.cookies.jwt_error) { + error = req.cookies.jwt_error; + res.clearCookie('jwt_error'); + } + res.render("home.ejs", {siteconfig: siteconfig, user: user, dicts: dicts, error: error}); }); }); }); @@ -286,6 +292,35 @@ app.post(siteconfig.rootPath+"dicts/dictread.json", function(req, res){ }); }); +//SKETCHENGINE LOGIN JSON endpoint: +app.get(siteconfig.rootPath+"skelogin.json/:token", function(req, res){ + //var token = req.headers.authorization.replace('Bearer ', ''); + var token = req.params.token; + var secret = siteconfig.sketchengineKey; + jwt.verify(token, secret, {audience:'lexonomy.eu'}, function(err, decoded) { + if (err == null) { + console.log(decoded) + ops.verifyLogin(req.cookies.email, req.cookies.sessionkey, function(user){ + ops.processJWT(user, decoded, function(success, email, sessionkey){ + if (success) { + res.cookie("email", email, {}); + res.cookie("sessionkey", sessionkey, {}); + res.redirect(siteconfig.baseUrl) + } else { + res.cookie("jwt_error", email, {}); + res.redirect(siteconfig.baseUrl) + } + }); + }); + } else { + //JWT not verified, error + res.cookie("jwt_error",err.message,{}) + res.redirect(siteconfig.baseUrl) + } + }); +}); + + //ONE-CLICK UI and JSON endpoints: app.get(siteconfig.rootPath+"oneclick/", function(req, res){ ops.verifyLogin(req.cookies.email, req.cookies.sessionkey, function(user){ diff --git a/website/ops.js b/website/ops.js index ac412a8d..76b45a38 100644 --- a/website/ops.js +++ b/website/ops.js @@ -995,20 +995,63 @@ module.exports={ } }); }, + processJWT: function(user, jwtData, callnext){ + var db = new sqlite3.Database(path.join(module.exports.siteconfig.dataDir, "lexonomy.sqlite"), sqlite3.OPEN_READWRITE); + if (user.loggedin) { + //user logged in = save SkE ID in database + var key = generateKey(); + var now = (new Date()).toISOString(); + db.run("update users set ske_id=$ske_id, ske_username=$ske_username, sessionKey=$key, sessionLast=$now where email=$email", {$ske_id: jwtData.user.id, $ske_username: jwtData.user.username, $email:user.email, $key:key, $now:now}, function(err, row){ + db.close(); + callnext(true, user.email, key); + }); + } else { + //user not logged in = + // if SkE ID in database = log in user + // if SkE ID not in database = register and log in user + db.get("select email from users where ske_id=$ske_id", {$ske_id: jwtData.user.id}, function(err, row){ + if (!row) { + var email = jwtData.user.username + '@sketchengine.co.uk'; + db.get("select * from users where email=$email", {$email: email}, function(err, row){ + if (row == undefined) { + var key = generateKey(); + var now = (new Date()).toISOString(); + db.run("insert into users (email, passwordHash, ske_id, ske_username, sessionKey, sessionLast) values ($email, null, $ske_id, $ske_username, $key, $now)", {$ske_id: jwtData.user.id, $ske_username: jwtData.user.username, $email: email, $key:key, $now:now}, function(err, row){ + db.close(); + callnext(true, email, key); + }); + } else { + db.close(); + callnext(false, "user already exists "+email, ""); + } + }); + } else { + var email = row.email; + var key = generateKey(); + var now = (new Date()).toISOString(); + db.run("update users set sessionKey=$key, sessionLast=$now where ske_id=$ske_id", {$key: key, $now: now, $ske_id: jwtData.user.id}, function(err, row){ + db.close(); + callnext(true, email, key); + }); + } + }); + } + }, verifyLogin: function(email, sessionkey, callnext){ var yesterday=(new Date()); yesterday.setHours(yesterday.getHours()-24); yesterday=yesterday.toISOString(); var db=new sqlite3.Database(path.join(module.exports.siteconfig.dataDir, "lexonomy.sqlite"), sqlite3.OPEN_READWRITE); - db.get("select email from users where email=$email and sessionKey=$key and sessionLast>=$yesterday", {$email: email, $key: sessionkey, $yesterday: yesterday}, function(err, row){ + db.get("select email, ske_username from users where email=$email and sessionKey=$key and sessionLast>=$yesterday", {$email: email, $key: sessionkey, $yesterday: yesterday}, function(err, row){ if(!row || module.exports.siteconfig.readonly){ db.close(); callnext({loggedin: false, email: null}); } else { email=row.email; + var ske_username = row.ske_username; var now=(new Date()).toISOString(); db.run("update users set sessionLast=$now where email=$email", {$now: now, $email: email}, function(err, row){ db.close(); module.exports.readSiteConfig(function(siteconfig){ - callnext({loggedin: true, email: email, isAdmin: (siteconfig.admins.indexOf(email)>-1)}); + callnext({loggedin: true, email: email, ske_username: ske_username, isAdmin: (siteconfig.admins.indexOf(email)>-1)}); }); }); } diff --git a/website/package-lock.json b/website/package-lock.json index d4f20959..65b2a559 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -48,6 +48,11 @@ "type-is": "1.6.16" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "busboy": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", @@ -172,6 +177,14 @@ "streamsearch": "0.1.2" } }, + "ecdsa-sig-formatter": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", + "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", + "requires": { + "safe-buffer": "5.1.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -324,6 +337,49 @@ "graceful-fs": "4.1.11" } }, + "jsonwebtoken": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.2.2.tgz", + "integrity": "sha512-rFFq7ow/JpPzwgaz4IyRL9cp7f4ptjW92eZgsQyqkysLBmDjSSBhnKfQESoq0GU+qJXK/CQ0o4shgwbUPiFCdw==", + "requires": { + "jws": "3.1.5", + "lodash.includes": "4.3.0", + "lodash.isboolean": "3.0.3", + "lodash.isinteger": "4.0.4", + "lodash.isnumber": "3.0.3", + "lodash.isplainobject": "4.0.6", + "lodash.isstring": "4.0.1", + "lodash.once": "4.1.1", + "ms": "2.1.1", + "xtend": "4.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "jwa": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz", + "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.10", + "safe-buffer": "5.1.1" + } + }, + "jws": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz", + "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==", + "requires": { + "jwa": "1.1.6", + "safe-buffer": "5.1.1" + } + }, "libxmljs-mt": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/libxmljs-mt/-/libxmljs-mt-0.18.0.tgz", @@ -343,6 +399,41 @@ "nan": "2.9.2" } }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "markdown": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/markdown/-/markdown-0.5.0.tgz", diff --git a/website/package.json b/website/package.json index a10167a5..1cd8005a 100644 --- a/website/package.json +++ b/website/package.json @@ -4,6 +4,7 @@ "ejs": "^2.5.7", "express": "^4.16.3", "fs-extra": "^5.0.0", + "jsonwebtoken": "^8.2.2", "libxslt": "^0.7.0", "markdown": "^0.5.0", "multer": "^1.3.0", diff --git a/website/siteconfig.json.template b/website/siteconfig.json.template index 49334a79..b8e0ed39 100644 --- a/website/siteconfig.json.template +++ b/website/siteconfig.json.template @@ -9,6 +9,8 @@ "trackingCode": "", "welcome": "Welcome to your Lexonomy installation.", "mailconfig": {"host": "smtp.server.example", "port": 465,"secure": true}, + "sketchengineKey": null, + "sketchengineLoginPage": null, "licences": { "cc-by-4.0": { "title": "Creative Commons Attribution 4.0 International", diff --git a/website/views/home.ejs b/website/views/home.ejs index 896dfc4a..9966d4ac 100644 --- a/website/views/home.ejs +++ b/website/views/home.ejs @@ -73,6 +73,12 @@ }); }); + <%if(error){%>
Sketch Engine login error: <%=error%>
<%}%> + <%if(siteconfig.sketchengineLoginPage){%> + + <%}%> <%}else{%>
<%=user.email%>
@@ -92,6 +98,16 @@
One-Click Dictionary settings
+ <%if(siteconfig.sketchengineLoginPage){%> +
SketchEngine login
+ + <%}%> <%if(user.isAdmin){%>
Administration
From 6ba111c104c2127d3e4ed41a4a761150fccc7584 Mon Sep 17 00:00:00 2001 From: Adam Rambousek Date: Tue, 12 Jun 2018 15:48:59 +0200 Subject: [PATCH 7/7] resolve conflict with main --- website/lexonomy.js | 2 +- website/siteconfig.json.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/lexonomy.js b/website/lexonomy.js index 6f32b697..d7145cd4 100644 --- a/website/lexonomy.js +++ b/website/lexonomy.js @@ -20,7 +20,7 @@ const querystring=require("querystring"); const libxslt=require("libxslt"); //https://www.npmjs.com/package/libxslt const sqlite3 = require('sqlite3').verbose(); //https://www.npmjs.com/package/sqlite3 const nodemailer = require('nodemailer'); -ops.mailtransporter = nodemailer.createTransport(siteconfig.mailconfig); + ops.mailtransporter = nodemailer.createTransport(siteconfig.mailconfig); const PORT=process.env.PORT||siteconfig.port||80; const jwt = require("jsonwebtoken"); diff --git a/website/siteconfig.json.template b/website/siteconfig.json.template index b8e0ed39..b0f3a749 100644 --- a/website/siteconfig.json.template +++ b/website/siteconfig.json.template @@ -8,7 +8,7 @@ "admins": ["root@localhost"], "trackingCode": "", "welcome": "Welcome to your Lexonomy installation.", - "mailconfig": {"host": "smtp.server.example", "port": 465,"secure": true}, + "mailconfig": {"host": "smtp.server.example", "port": 465,"secure": true, "from": "noreply@example.com"}, "sketchengineKey": null, "sketchengineLoginPage": null, "licences": {