mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Dont use QueryPerfomanceCounter for monotonic() as it is wildly inaccurate, despite what the documentation from MuppetSoft says
This commit is contained in:
parent
06c5f0c1f2
commit
b7f0999949
@ -9,6 +9,7 @@ __copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
import binascii, os, random, struct, base64, httplib
|
||||
from hashlib import md5, sha256
|
||||
from itertools import permutations
|
||||
from threading import Lock
|
||||
|
||||
from calibre.srv.errors import HTTPAuthRequired, HTTPSimpleResponse, InvalidCredentials
|
||||
from calibre.srv.http_request import parse_uri
|
||||
@ -16,6 +17,7 @@ from calibre.srv.utils import parse_http_dict, encode_path
|
||||
from calibre.utils.monotonic import monotonic
|
||||
|
||||
MAX_AGE_SECONDS = 3600
|
||||
nonce_counter, nonce_counter_lock = 0, Lock()
|
||||
|
||||
def as_bytestring(x):
|
||||
if not isinstance(x, bytes):
|
||||
@ -34,12 +36,18 @@ def base64_decode(s):
|
||||
def synthesize_nonce(key_order, realm, secret, timestamp=None):
|
||||
'''
|
||||
Create a nonce. Can be used for either digest or cookie based auth.
|
||||
The nonce is of the form timestamp:hash with has being a hash of the
|
||||
The nonce is of the form timestamp:hash with hash being a hash of the
|
||||
timestamp, server secret and realm. This allows the timestamp to be
|
||||
validated and stale nonce's to be rejected.
|
||||
'''
|
||||
if timestamp is None:
|
||||
timestamp = binascii.hexlify(struct.pack(b'!d', float(monotonic())))
|
||||
global nonce_counter
|
||||
with nonce_counter_lock:
|
||||
nonce_counter += 1
|
||||
# The resolution of monotonic() on windows is very low (10s of
|
||||
# milliseconds) so to ensure nonce values are not re-used, we have a
|
||||
# global counter
|
||||
timestamp = binascii.hexlify(struct.pack(b'!dQ', float(monotonic()), nonce_counter))
|
||||
h = sha256_hex(key_order.format(timestamp, realm, secret))
|
||||
nonce = ':'.join((timestamp, h))
|
||||
return nonce
|
||||
@ -51,7 +59,7 @@ def validate_nonce(key_order, nonce, realm, secret):
|
||||
|
||||
def is_nonce_stale(nonce, max_age_seconds=MAX_AGE_SECONDS):
|
||||
try:
|
||||
timestamp = struct.unpack(b'!d', binascii.unhexlify(as_bytestring(nonce.partition(':')[0])))[0]
|
||||
timestamp = struct.unpack(b'!dQ', binascii.unhexlify(as_bytestring(nonce.partition(':')[0])))[0]
|
||||
return timestamp + max_age_seconds < monotonic()
|
||||
except Exception:
|
||||
pass
|
||||
|
@ -217,8 +217,8 @@ class LoopTest(BaseTest):
|
||||
b = monotonic()
|
||||
self.assertGreaterEqual(b, a)
|
||||
a = monotonic()
|
||||
time.sleep(0.01)
|
||||
time.sleep(0.1)
|
||||
b = monotonic()
|
||||
self.assertGreaterEqual(b, a)
|
||||
self.assertGreaterEqual(b - a, 0.01)
|
||||
self.assertLessEqual(b - a, 0.02)
|
||||
self.assertGreaterEqual(b - a, 0.09)
|
||||
self.assertLessEqual(b - a, 0.2)
|
||||
|
@ -26,17 +26,20 @@
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <Windows.h>
|
||||
static LARGE_INTEGER frequency = {0}, ts = {0};
|
||||
|
||||
/* static PyObject* monotonic(PyObject *self, PyObject *args) { */
|
||||
/* return PyFloat_FromDouble(((double)GetTickCount64())/SEC_TO_MS); */
|
||||
/* } */
|
||||
|
||||
static PyObject* monotonic(PyObject *self, PyObject *args) {
|
||||
if (!QueryPerformanceCounter(&ts)) { PyErr_SetFromWindowsErr(0); return NULL; }
|
||||
return PyFloat_FromDouble(((double)ts.QuadPart)/frequency.QuadPart);
|
||||
return PyFloat_FromDouble(((double)GetTickCount64())/SEC_TO_MS);
|
||||
}
|
||||
|
||||
/* QueryPerformanceCounter() is wildly inaccurate, so we use the more stable
|
||||
* the lower resolution GetTickCount64() (this is what python 3.x uses)
|
||||
* static LARGE_INTEGER frequency = {0}, ts = {0};
|
||||
* static PyObject* monotonic(PyObject *self, PyObject *args) {
|
||||
* if (!QueryPerformanceCounter(&ts)) { PyErr_SetFromWindowsErr(0); return NULL; }
|
||||
* return PyFloat_FromDouble(((double)ts.QuadPart)/frequency.QuadPart);
|
||||
* }
|
||||
*/
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
static mach_timebase_info_data_t timebase = {0};
|
||||
@ -72,7 +75,7 @@ PyMODINIT_FUNC
|
||||
initmonotonic(void) {
|
||||
PyObject *m;
|
||||
#ifdef _MSC_VER
|
||||
if(!QueryPerformanceFrequency(&frequency)) { PyErr_SetFromWindowsErr(0); return; }
|
||||
/* if(!QueryPerformanceFrequency(&frequency)) { PyErr_SetFromWindowsErr(0); return; } */
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
mach_timebase_info(&timebase);
|
||||
|
Loading…
x
Reference in New Issue
Block a user