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
|
import binascii, os, random, struct, base64, httplib
|
||||||
from hashlib import md5, sha256
|
from hashlib import md5, sha256
|
||||||
from itertools import permutations
|
from itertools import permutations
|
||||||
|
from threading import Lock
|
||||||
|
|
||||||
from calibre.srv.errors import HTTPAuthRequired, HTTPSimpleResponse, InvalidCredentials
|
from calibre.srv.errors import HTTPAuthRequired, HTTPSimpleResponse, InvalidCredentials
|
||||||
from calibre.srv.http_request import parse_uri
|
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
|
from calibre.utils.monotonic import monotonic
|
||||||
|
|
||||||
MAX_AGE_SECONDS = 3600
|
MAX_AGE_SECONDS = 3600
|
||||||
|
nonce_counter, nonce_counter_lock = 0, Lock()
|
||||||
|
|
||||||
def as_bytestring(x):
|
def as_bytestring(x):
|
||||||
if not isinstance(x, bytes):
|
if not isinstance(x, bytes):
|
||||||
@ -34,12 +36,18 @@ def base64_decode(s):
|
|||||||
def synthesize_nonce(key_order, realm, secret, timestamp=None):
|
def synthesize_nonce(key_order, realm, secret, timestamp=None):
|
||||||
'''
|
'''
|
||||||
Create a nonce. Can be used for either digest or cookie based auth.
|
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
|
timestamp, server secret and realm. This allows the timestamp to be
|
||||||
validated and stale nonce's to be rejected.
|
validated and stale nonce's to be rejected.
|
||||||
'''
|
'''
|
||||||
if timestamp is None:
|
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))
|
h = sha256_hex(key_order.format(timestamp, realm, secret))
|
||||||
nonce = ':'.join((timestamp, h))
|
nonce = ':'.join((timestamp, h))
|
||||||
return nonce
|
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):
|
def is_nonce_stale(nonce, max_age_seconds=MAX_AGE_SECONDS):
|
||||||
try:
|
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()
|
return timestamp + max_age_seconds < monotonic()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
@ -217,8 +217,8 @@ class LoopTest(BaseTest):
|
|||||||
b = monotonic()
|
b = monotonic()
|
||||||
self.assertGreaterEqual(b, a)
|
self.assertGreaterEqual(b, a)
|
||||||
a = monotonic()
|
a = monotonic()
|
||||||
time.sleep(0.01)
|
time.sleep(0.1)
|
||||||
b = monotonic()
|
b = monotonic()
|
||||||
self.assertGreaterEqual(b, a)
|
self.assertGreaterEqual(b, a)
|
||||||
self.assertGreaterEqual(b - a, 0.01)
|
self.assertGreaterEqual(b - a, 0.09)
|
||||||
self.assertLessEqual(b - a, 0.02)
|
self.assertLessEqual(b - a, 0.2)
|
||||||
|
@ -26,17 +26,20 @@
|
|||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include <Windows.h>
|
#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) {
|
static PyObject* monotonic(PyObject *self, PyObject *args) {
|
||||||
if (!QueryPerformanceCounter(&ts)) { PyErr_SetFromWindowsErr(0); return NULL; }
|
return PyFloat_FromDouble(((double)GetTickCount64())/SEC_TO_MS);
|
||||||
return PyFloat_FromDouble(((double)ts.QuadPart)/frequency.QuadPart);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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__)
|
#elif defined(__APPLE__)
|
||||||
#include <mach/mach_time.h>
|
#include <mach/mach_time.h>
|
||||||
static mach_timebase_info_data_t timebase = {0};
|
static mach_timebase_info_data_t timebase = {0};
|
||||||
@ -72,7 +75,7 @@ PyMODINIT_FUNC
|
|||||||
initmonotonic(void) {
|
initmonotonic(void) {
|
||||||
PyObject *m;
|
PyObject *m;
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
if(!QueryPerformanceFrequency(&frequency)) { PyErr_SetFromWindowsErr(0); return; }
|
/* if(!QueryPerformanceFrequency(&frequency)) { PyErr_SetFromWindowsErr(0); return; } */
|
||||||
#endif
|
#endif
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
mach_timebase_info(&timebase);
|
mach_timebase_info(&timebase);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user