Completed
Push — master ( 30829d...cf89eb )
by Messense
22:52 queued 22:20
created

get_querystring()   A

Complexity

Conditions 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 1
c 3
b 1
f 0
dl 0
loc 8
ccs 3
cts 3
cp 1
crap 1
rs 9.4285
1
# -*- coding: utf-8 -*-
2 10
"""
3
    wechatpy.utils
4
    ~~~~~~~~~~~~~~~
5
6
    This module provides some useful utilities.
7
8
    :copyright: (c) 2014 by messense.
9
    :license: MIT, see LICENSE for more details.
10
"""
11 10
from __future__ import absolute_import, unicode_literals
12 10
import string
13 10
import random
14 10
import hashlib
15
16 10
try:
17
    '''Use simplejson if we can, fallback to json otherwise.'''
18 10
    import simplejson as json
19 10
except ImportError:
20 10
    import json  # NOQA
21
22 10
import six
23 10
import six.moves.urllib.parse as urlparse
24
25
26 10
class ObjectDict(dict):
27
    """Makes a dictionary behave like an object, with attribute-style access.
28
    """
29
30 10
    def __getattr__(self, key):
31 10
        if key in self:
32 10
            return self[key]
33 10
        return None
34
35 10
    def __setattr__(self, key, value):
36 10
        self[key] = value
37
38
39 10
class WeChatSigner(object):
40
    """WeChat data signer"""
41
42 10
    def __init__(self, delimiter=b''):
43 10
        self._data = []
44 10
        self._delimiter = to_binary(delimiter)
45
46 10
    def add_data(self, *args):
47
        """Add data to signer"""
48 10
        for data in args:
49 10
            self._data.append(to_binary(data))
50
51 10
    @property
52
    def signature(self):
53
        """Get data signature"""
54 10
        self._data.sort()
55 10
        str_to_sign = self._delimiter.join(self._data)
56 10
        return hashlib.sha1(str_to_sign).hexdigest()
57
58
59 10
def check_signature(token, signature, timestamp, nonce):
60
    """Check WeChat callback signature, raises InvalidSignatureException
61
    if check failed.
62
63
    :param token: WeChat callback token
64
    :param signature: WeChat callback signature sent by WeChat server
65
    :param timestamp: WeChat callback timestamp sent by WeChat server
66
    :param nonce: WeChat callback nonce sent by WeChat sever
67
    """
68 10
    signer = WeChatSigner()
69 10
    signer.add_data(token, timestamp, nonce)
70 10
    if signer.signature != signature:
71 10
        from wechatpy.exceptions import InvalidSignatureException
72
73 10
        raise InvalidSignatureException()
74
75
76 10
def to_text(value, encoding='utf-8'):
77
    """Convert value to unicode, default encoding is utf-8
78
79
    :param value: Value to be converted
80
    :param encoding: Desired encoding
81
    """
82 10
    if not value:
83 10
        return ''
84 10
    if isinstance(value, six.text_type):
85 10
        return value
86 10
    if isinstance(value, six.binary_type):
87 10
        return value.decode(encoding)
88 10
    return six.text_type(value)
89
90
91 10
def to_binary(value, encoding='utf-8'):
92
    """Convert value to binary string, default encoding is utf-8
93
94
    :param value: Value to be converted
95
    :param encoding: Desired encoding
96
    """
97 10
    if not value:
98 10
        return b''
99 10
    if isinstance(value, six.binary_type):
100 10
        return value
101 10
    if isinstance(value, six.text_type):
102 10
        return value.encode(encoding)
103
    return six.binary_type(value)
104
105
106 10
def timezone(zone):
107
    """Try to get timezone using pytz or python-dateutil
108
109
    :param zone: timezone str
110
    :return: timezone tzinfo or None
111
    """
112 10
    try:
113 10
        import pytz
114
        return pytz.timezone(zone)
115 10
    except ImportError:
116 10
        pass
117 10
    try:
118 10
        from dateutil.tz import gettz
119 10
        return gettz(zone)
120
    except ImportError:
121
        return None
122
123
124 10
def random_string(length=16):
125 10
    rule = string.ascii_letters + string.digits
126 10
    rand_list = random.sample(rule, length)
127 10
    return ''.join(rand_list)
128
129
130 10
def get_querystring(uri):
131
    """Get Querystring information from uri.
132
133
    :param uri: uri
134
    :return: querystring info or {}
135
    """
136 10
    parts = urlparse.urlsplit(uri)
137 10
    return urlparse.parse_qs(parts.query)
138
139
140 10
def byte2int(c):
141 10
    if six.PY2:
142 4
        return ord(c)
143
    return c
144