Mercurial > templog
comparison web/secure.py @ 586:87c20b8c5472 default master
port to python3
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Mon, 09 Sep 2019 22:24:10 +0800 |
parents | a99631597f65 |
children |
comparison
equal
deleted
inserted
replaced
585:1c484dab4e83 | 586:87c20b8c5472 |
---|---|
1 import re | 1 import re |
2 import os | 2 import os |
3 import time | 3 import time |
4 import fcntl | 4 import fcntl |
5 import hmac | 5 import hmac |
6 import binascii | |
7 import sys | 6 import sys |
8 import hashlib | 7 import hashlib |
9 | 8 |
10 import bottle | 9 import bottle |
11 | 10 |
25 HASH=hashlib.sha1 | 24 HASH=hashlib.sha1 |
26 | 25 |
27 CLEAN_RE = re.compile('[^a-z0-9A-Z]') | 26 CLEAN_RE = re.compile('[^a-z0-9A-Z]') |
28 | 27 |
29 def cookie_hash(c): | 28 def cookie_hash(c): |
30 return hashlib.sha256(c).hexdigest() | 29 return hashlib.sha256(c.encode()).hexdigest() |
31 | 30 |
32 def init_cookie(): | 31 def init_cookie(): |
33 """ Generates a new httponly auth cookie if required. | 32 """ Generates a new httponly auth cookie if required. |
34 Returns the hash of the cookie (new or existing) | 33 Returns the hash of the cookie (new or existing) |
35 """ | 34 """ |
36 c = bottle.request.get_cookie(AUTH_COOKIE) | 35 c = bottle.request.get_cookie(AUTH_COOKIE) |
37 if not c: | 36 if not c: |
38 c = binascii.hexlify(os.urandom(AUTH_COOKIE_LEN)) | 37 c = os.urandom(AUTH_COOKIE_LEN).hex() |
39 years = 60*60*24*365 | 38 years = 60*60*24*365 |
40 bottle.response.set_cookie(AUTH_COOKIE, c, secure=True, httponly=True, max_age=10*years) | 39 bottle.response.set_cookie(AUTH_COOKIE, c, secure=True, httponly=True, max_age=10*years) |
41 return cookie_hash(c) | 40 return cookie_hash(c) |
42 | 41 |
43 def check_cookie(allowed_users): | 42 def check_cookie(allowed_users): |
47 return cookie_hash(c) in allowed_users | 46 return cookie_hash(c) in allowed_users |
48 | 47 |
49 def setup_csrf(): | 48 def setup_csrf(): |
50 NONCE_SIZE=16 | 49 NONCE_SIZE=16 |
51 global _csrf_fd, _csrf_key | 50 global _csrf_fd, _csrf_key |
52 _csrf_fd = os.fdopen(os.open('%s/csrf.dat' % config.DATA_PATH, os.O_RDWR | os.O_CREAT, 0600), 'r+') | 51 _csrf_fd = os.fdopen(os.open('%s/csrf.dat' % config.DATA_PATH, os.O_RDWR | os.O_CREAT, 0o600), 'r+') |
53 | 52 |
54 try: | 53 try: |
55 fcntl.lockf(_csrf_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) | 54 fcntl.lockf(_csrf_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) |
56 _csrf_fd.write("%d-%s" % (os.getpid(), binascii.hexlify(os.urandom(NONCE_SIZE)))) | 55 _csrf_fd.write("%d-%s" % (os.getpid(), os.urandom(NONCE_SIZE).hex())) |
57 _csrf_fd.flush() | 56 _csrf_fd.flush() |
58 _csrf_fd.seek(0) | 57 _csrf_fd.seek(0) |
59 except IOError: | 58 except IOError: |
60 pass | 59 pass |
61 fcntl.lockf(_csrf_fd, fcntl.LOCK_SH) | 60 fcntl.lockf(_csrf_fd, fcntl.LOCK_SH) |
64 | 63 |
65 | 64 |
66 def get_csrf_blob(): | 65 def get_csrf_blob(): |
67 expiry = int(config.CSRF_TIMEOUT + time.time()) | 66 expiry = int(config.CSRF_TIMEOUT + time.time()) |
68 content = '%s-%s' % (init_cookie(), expiry) | 67 content = '%s-%s' % (init_cookie(), expiry) |
69 mac = hmac.new(_csrf_key, content).hexdigest() | 68 mac = hmac.new(_csrf_key.encode(), content.encode()).hexdigest() |
70 return "%s-%s" % (content, mac) | 69 return "%s-%s" % (content, mac) |
71 | 70 |
72 def check_csrf_blob(blob): | 71 def check_csrf_blob(blob): |
73 toks = blob.split('-') | 72 toks = blob.split('-') |
74 if len(toks) != 3: | 73 if len(toks) != 3: |
75 print>>sys.stderr, "wrong toks" | |
76 return False | 74 return False |
77 | 75 |
78 user, expiry, mac = toks | 76 user, expiry, mac = toks |
79 if user != init_cookie(): | 77 if user != init_cookie(): |
80 print>>sys.stderr, "wrong user" | |
81 return False | 78 return False |
82 | 79 |
83 try: | 80 try: |
84 exp = int(expiry) | 81 exp = int(expiry) |
85 except ValueError: | 82 except ValueError: |
86 print>>sys.stderr, "failed exp" | |
87 return False | 83 return False |
88 | 84 |
89 if exp < 1000000000: | 85 if exp < 1000000000: |
90 return False | 86 return False |
91 | 87 |
92 if exp < time.time(): | 88 if exp < time.time(): |
93 print>>sys.stderr, "expired %d %d" % (exp, time.time()) | |
94 return False | 89 return False |
95 | 90 |
96 check_content = "%s-%s" % (user, expiry) | 91 check_content = "%s-%s" % (user, expiry) |
97 check_mac = hmac.new(_csrf_key, check_content).hexdigest() | 92 check_mac = hmac.new(_csrf_key.encode(), check_content.encode()).hexdigest() |
98 if mac == check_mac: | 93 if mac == check_mac: |
99 print>>sys.stderr, "good hmac" | |
100 return True | 94 return True |
101 | 95 |
102 print>>sys.stderr, "fail" | |
103 return False | 96 return False |
104 | 97 |