Mercurial > hg > index.fcgi > www > www-1
changeset 78:f833a888c548
add cookie-based PIN system, and update laterlinks to use it
author | paulo |
---|---|
date | Thu, 02 Jun 2016 00:27:50 -0700 |
parents | 6ede61cb9d12 |
children | 01cf0e93c914 |
files | cs/cookies.js cs/index.html laterlinks2/laterlinks_app.py laterlinks2/pinlib.py |
diffstat | 4 files changed, 183 insertions(+), 18 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/cs/cookies.js Thu Jun 02 00:27:50 2016 -0700 1.3 @@ -0,0 +1,63 @@ 1.4 +/*\ 1.5 +|*| 1.6 +|*| :: cookies.js :: 1.7 +|*| 1.8 +|*| A complete cookies reader/writer framework with full unicode support. 1.9 +|*| 1.10 +|*| Revision #1 - September 4, 2014 1.11 +|*| 1.12 +|*| https://developer.mozilla.org/en-US/docs/Web/API/document.cookie 1.13 +|*| https://developer.mozilla.org/User:fusionchess 1.14 +|*| 1.15 +|*| This framework is released under the GNU Public License, version 3 or later. 1.16 +|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html 1.17 +|*| 1.18 +|*| Syntaxes: 1.19 +|*| 1.20 +|*| * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]]) 1.21 +|*| * docCookies.getItem(name) 1.22 +|*| * docCookies.removeItem(name[, path[, domain]]) 1.23 +|*| * docCookies.hasItem(name) 1.24 +|*| * docCookies.keys() 1.25 +|*| 1.26 +\*/ 1.27 + 1.28 +var docCookies = { 1.29 + getItem: function (sKey) { 1.30 + if (!sKey) { return null; } 1.31 + return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; 1.32 + }, 1.33 + setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { 1.34 + if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } 1.35 + var sExpires = ""; 1.36 + if (vEnd) { 1.37 + switch (vEnd.constructor) { 1.38 + case Number: 1.39 + sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; 1.40 + break; 1.41 + case String: 1.42 + sExpires = "; expires=" + vEnd; 1.43 + break; 1.44 + case Date: 1.45 + sExpires = "; expires=" + vEnd.toUTCString(); 1.46 + break; 1.47 + } 1.48 + } 1.49 + document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); 1.50 + return true; 1.51 + }, 1.52 + removeItem: function (sKey, sPath, sDomain) { 1.53 + if (!this.hasItem(sKey)) { return false; } 1.54 + document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); 1.55 + return true; 1.56 + }, 1.57 + hasItem: function (sKey) { 1.58 + if (!sKey) { return false; } 1.59 + return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); 1.60 + }, 1.61 + keys: function () { 1.62 + var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/); 1.63 + for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); } 1.64 + return aKeys; 1.65 + } 1.66 +};
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/cs/index.html Thu Jun 02 00:27:50 2016 -0700 2.3 @@ -0,0 +1,74 @@ 2.4 +<html> 2.5 +<head> 2.6 +<link rel="stylesheet" type="text/css" href="index.css"> 2.7 +<script type="text/javascript" src="cookies.js"></script> 2.8 +</head> 2.9 + 2.10 +<body> 2.11 +<h1>Cookies set</h1> 2.12 +<div id="set_cookies"></div> 2.13 +<div> 2.14 + <input id="set_k"> 2.15 + <input type="password" id="set_v"> 2.16 + <input type="button" value="Set" onclick="set()"> 2.17 +</div> 2.18 +</body> 2.19 +<script type="text/javascript"> 2.20 +var setCookiesDiv = document.getElementById("set_cookies"); 2.21 +var setK = document.getElementById("set_k"); 2.22 +var setV = document.getElementById("set_v"); 2.23 + 2.24 +function addSetCookie(k, v) { 2.25 + var d = document.createElement("div"); 2.26 + 2.27 + var kInput = document.createElement("input"); 2.28 + kInput.disabled = true; 2.29 + kInput.value = k; 2.30 + 2.31 + var vInput = document.createElement("input"); 2.32 + vInput.type = "password"; 2.33 + vInput.disabled = true; 2.34 + vInput.value = v; 2.35 + 2.36 + var unset = document.createElement("input"); 2.37 + unset.type = "button"; 2.38 + unset.value = "Unset"; 2.39 + unset.onclick = function() { 2.40 + docCookies.removeItem(k); 2.41 + setCookiesDiv.removeChild(d); 2.42 + }; 2.43 + 2.44 + d.appendChild(kInput); 2.45 + d.appendChild(vInput); 2.46 + d.appendChild(unset); 2.47 + 2.48 + setCookiesDiv.appendChild(d); 2.49 +} 2.50 + 2.51 +function clear() { 2.52 + while (setCookiesDiv.firstChild) { 2.53 + setCookiesDiv.removeChild(setCookiesDiv.firstChild); 2.54 + } 2.55 +} 2.56 + 2.57 +function load() { 2.58 + clear(); 2.59 + for (var i=0; i<docCookies.keys().length; i++) { 2.60 + var k = docCookies.keys()[i]; 2.61 + if (docCookies.hasItem(k)) { 2.62 + var v = docCookies.getItem(k); 2.63 + addSetCookie(k, v); 2.64 + } 2.65 + } 2.66 +} 2.67 + 2.68 +function set() { 2.69 + docCookies.setItem(setK.value, setV.value, 600); 2.70 + setK.value = ""; 2.71 + setV.value = ""; 2.72 + load(); 2.73 +} 2.74 + 2.75 +load(); 2.76 +</script> 2.77 +</html>
3.1 --- a/laterlinks2/laterlinks_app.py Tue May 31 23:40:17 2016 -0600 3.2 +++ b/laterlinks2/laterlinks_app.py Thu Jun 02 00:27:50 2016 -0700 3.3 @@ -6,10 +6,11 @@ 3.4 3.5 import html 3.6 3.7 +import pinlib 3.8 + 3.9 3.10 DEBUG = True 3.11 STRTIME_FMT = "%Y-%m-%d %H:%M:%S" 3.12 -MY_PIN = "qworpy" 3.13 3.14 3.15 class LLDialect(csv.Dialect): 3.16 @@ -79,24 +80,17 @@ 3.17 return urlparse.parse_qs(environ["wsgi.input"].read()) 3.18 3.19 3.20 -def get_pin(inp): 3.21 - if "pin" not in inp: 3.22 - raise PinFailError() 3.23 - 3.24 - pin = inp["pin"][0] 3.25 - if pin != MY_PIN: 3.26 - raise PinFailError() 3.27 - 3.28 - return pin 3.29 - 3.30 3.31 def main(environ): 3.32 - pin = '' 3.33 is_post = (environ["REQUEST_METHOD"] == "POST") 3.34 + cookies = pinlib.parse_cookies(environ) 3.35 inp = parse_wsgi_input(environ) 3.36 3.37 if is_post: 3.38 - pin = get_pin(inp) 3.39 + try: 3.40 + pinlib.check(cookies) 3.41 + except pinlib.PinFailError: 3.42 + raise PinFailError 3.43 if inp["submit"][0] == "Add": 3.44 lldb_add(inp) 3.45 elif inp["submit"][0] == "Delete": 3.46 @@ -118,7 +112,8 @@ 3.47 for i in environ.items(): 3.48 debug += cgi.escape("%s = %s \n" % i) 3.49 3.50 - debug += cgi.escape("wsgi.input.read = %s" % inp) 3.51 + debug += cgi.escape("wsgi.input.read = %s \n" % inp) 3.52 + debug += cgi.escape("cookies = %s \n" % cookies) 3.53 3.54 form = body.form(action="index.fcgi", method="post") 3.55 3.56 @@ -142,9 +137,6 @@ 3.57 p1.br 3.58 p1.input(type="submit", name="submit", value="Add") 3.59 3.60 - p2 = form.p 3.61 - p2.input(type="password", name="pin", value=pin) 3.62 - 3.63 return unicode(root).encode("utf-8") 3.64 3.65 3.66 @@ -154,7 +146,7 @@ 3.67 3.68 try: 3.69 response_body = main(environ) 3.70 - response_code = "200 OK" 3.71 + response_code = "200 OK" 3.72 response_type = "text/html; charset=UTF-8" 3.73 except LLError as e: 3.74 response_body = str(e)
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/laterlinks2/pinlib.py Thu Jun 02 00:27:50 2016 -0700 4.3 @@ -0,0 +1,36 @@ 4.4 +import urlparse 4.5 + 4.6 + 4.7 +PIN_KEY = "llpin" 4.8 +PIN_FN = "_%s" % PIN_KEY 4.9 + 4.10 + 4.11 +class PinFailError(Exception): 4.12 + pass 4.13 + 4.14 + 4.15 +def load(): 4.16 + ret = None 4.17 + 4.18 + try: 4.19 + with open(PIN_FN) as pin_f: 4.20 + ret = pin_f.read().strip() 4.21 + except IOError: 4.22 + pass 4.23 + 4.24 + return ret 4.25 + 4.26 + 4.27 +def parse_cookies(environ): 4.28 + return urlparse.parse_qs(environ.get("HTTP_COOKIE", "")) 4.29 + 4.30 + 4.31 +def check(cookies): 4.32 + if PIN_KEY not in cookies: 4.33 + raise PinFailError() 4.34 + 4.35 + pin = cookies[PIN_KEY][0] 4.36 + if pin != load(): 4.37 + raise PinFailError() 4.38 + 4.39 + return pin