-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge in machine ID into cookie name and pin generation
- Loading branch information
Showing
1 changed file
with
76 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,13 +9,15 @@ | |
:license: BSD, see LICENSE for more details. | ||
""" | ||
import os | ||
import re | ||
import sys | ||
import uuid | ||
import json | ||
import time | ||
import getpass | ||
import hashlib | ||
import mimetypes | ||
from itertools import chain | ||
from os.path import join, dirname, basename, isfile | ||
from werkzeug.wrappers import BaseRequest as Request, BaseResponse as Response | ||
from werkzeug.http import parse_cookie | ||
|
@@ -40,6 +42,59 @@ def hash_pin(pin): | |
return hashlib.md5(pin + 'shittysalt').hexdigest()[:12] | ||
|
||
|
||
_machine_id = None | ||
|
||
|
||
def get_machine_id(): | ||
global _machine_id | ||
rv = _machine_id | ||
if rv is not None: | ||
return rv | ||
|
||
def _generate(): | ||
# Potential sources of secret information on linux. The machine-id | ||
# is stable across boots, the boot id is not | ||
for filename in '/etc/machine-id', '/proc/sys/kernel/random/boot_id': | ||
try: | ||
with open(filename, 'rb') as f: | ||
f.readline().strip() | ||
This comment has been minimized.
Sorry, something went wrong. |
||
except IOError: | ||
continue | ||
|
||
# On OS X we can use the computer's serial number assuming that | ||
# ioreg exists and can spit out that information. | ||
from subprocess import Popen, PIPE | ||
try: | ||
dump = Popen(['ioreg', '-c', 'IOPlatformExpertDevice', '-d', '2'], | ||
stdout=PIPE).communicate()[0] | ||
match = re.match(r'"serial-number" = <([^>]+)', dump) | ||
if match is not None: | ||
return match.group(1) | ||
except OSError: | ||
pass | ||
|
||
# On Windows we can use winreg to get the machine guid | ||
wr = None | ||
try: | ||
import winreg as wr | ||
except ImportError: | ||
try: | ||
import _winreg as wr | ||
except ImportError: | ||
pass | ||
if wr is not None: | ||
try: | ||
with wr.OpenKey(wr.HKEY_LOCAL_MACHINE, | ||
'SOFTWARE\\Microsoft\\Cryptography', 0, | ||
wr.KEY_READ | wr.KEY_WOW64_64KEY) as rk: | ||
return wr.QueryValueEx(rk, 'MachineGuid')[0] | ||
except WindowsError: | ||
pass | ||
|
||
_machine_id = rv = _generate() | ||
return rv | ||
|
||
|
||
class _ConsoleFrame(object): | ||
|
||
"""Helper class so that we can reuse the frame console code for the | ||
|
@@ -85,30 +140,42 @@ def get_pin_and_cookie_name(app): | |
except ImportError: | ||
username = None | ||
|
||
bits = [ | ||
mod = sys.modules.get(modname) | ||
|
||
# This information only exists to make the cookie unique on the | ||
# computer, not as a security feature. | ||
probably_public_bits = [ | ||
username, | ||
str(uuid.getnode()), | ||
modname, | ||
getattr(app, '__name__', getattr(app.__class__, '__name__')), | ||
getattr(mod, '__file__', None), | ||
] | ||
|
||
mod = sys.modules.get(modname) | ||
bits.append(getattr(mod, '__file__', None)) | ||
bits.append('cookiesalt') | ||
# This information is here to make it harder for an attacker to | ||
# guess the cookie name. They are unlikely to be contained anywhere | ||
# within the unauthenticated debug page. | ||
private_bits = [ | ||
str(uuid.getnode()), | ||
get_machine_id(), | ||
] | ||
|
||
h = hashlib.md5() | ||
This comment has been minimized.
Sorry, something went wrong.
JordanMilne
|
||
for bit in bits: | ||
for bit in chain(probably_public_bits, private_bits): | ||
if not bit: | ||
continue | ||
if isinstance(bit, text_type): | ||
bit = bit.encode('utf-8') | ||
h.update(bit) | ||
h.update('cookiesalt') | ||
|
||
cookie_name = '__wzd' + h.hexdigest()[:20] | ||
This comment has been minimized.
Sorry, something went wrong. |
||
|
||
# If we need to generate a pin we salt it a bit more so that we don't | ||
# end up with the same value and generate out 9 digits | ||
if num is None: | ||
h.update('pinsalt') | ||
num = ('%09d' % int(h.hexdigest(), 16))[:9] | ||
|
||
cookie_name = '__wzd' + h.hexdigest()[:12] | ||
|
||
# Format the pincode in groups of digits for easier remembering if | ||
# we don't have a result yet. | ||
if rv is None: | ||
|
@@ -386,7 +453,7 @@ def __call__(self, environ, start_response): | |
response = self.log_pin_request() | ||
elif self.evalex and cmd is not None and frame is not None \ | ||
and self.secret == secret and \ | ||
self.is_trusted(environ): | ||
self.check_pin_trust(environ): | ||
response = self.execute_command(request, cmd, frame) | ||
elif self.evalex and self.console_path is not None and \ | ||
request.path == self.console_path: | ||
|
Should there be a
return
here?