Completed
Push — master ( e6b198...e30f90 )
by Messense
11:09 queued 10:06
created

wechatpy.to_binary()   A

Complexity

Conditions 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.0312
Metric Value
cc 4
dl 0
loc 13
ccs 7
cts 8
cp 0.875
crap 4.0312
rs 9.2
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
        return gettz(zone)
120 10
    except ImportError:
121 10
        return None
122
123
124 10
def random_string(length=16):
125
    rule = string.ascii_letters + string.digits
126
    rand_list = random.sample(rule, length)
127
    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 9
    parts = urlparse.urlsplit(uri)
137 9
    if sys.version_info[:2] == (2, 6):
138
        query = parts.path
139
        if query.startswith('?'):
140
            query = query[1:]
141
    else:
142 9
        query = parts.query
143 9
    return urlparse.parse_qs(query)
144
145
146 10
def byte2int(c):
147 10
    if six.PY2:
148 4
        return ord(c)
149
    return c
150