Completed
Pull Request — master (#195)
by
unknown
10:55 queued 09:47
created

random_string()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 4
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 six
13 10
import six.moves.urllib.parse as urlparse
14 10
import sys
15 10
import string
16 10
import random
17 10
import hashlib
18
19 10
try:
20
    '''Use simplejson if we can, fallback to json otherwise.'''
21 10
    import simplejson as json
22 10
except ImportError:
23 10
    import json  # NOQA
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 Qeruystring information from uri.
132
133
    :param uri: uri
134
    :return: querystring info or {}
135
    """
136 10
    parts = urlparse.urlsplit(uri)
137 10
    if sys.version_info[:2] == (2, 6):
138
        query = parts.path
139
        if query.startswith('?'):
140
            query = query[1:]
141
    else:
142 10
        query = parts.query
143 10
    return urlparse.parse_qs(query)
144
145
146 10
def byte2int(c):
147 10
    if six.PY2:
148 3
        return ord(c)
149
    return c
150