summaryrefslogtreecommitdiff
path: root/macaroonbakery/utils.py
blob: 43b0bf2ab66885d04c9114d86c4b7aa83922db8d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# Copyright 2017 Canonical Ltd.
# Licensed under the LGPLv3, see LICENCE file for details.
import base64
import json
import webbrowser
import six
import six.moves.http_cookiejar as http_cookiejar
from six.moves.urllib.parse import urlparse

from pymacaroons import Macaroon
from pymacaroons.serializers import json_serializer


def to_bytes(s):
    '''Return s as a bytes type, using utf-8 encoding if necessary.
    @param s string or bytes
    @return bytes
    '''
    if isinstance(s, six.binary_type):
        return s
    if isinstance(s, six.string_types):
        return s.encode('utf-8')
    raise TypeError('want string or bytes, got {}', type(s))


def macaroon_from_dict(json_macaroon):
    '''Return a pymacaroons.Macaroon object from the given
    JSON-deserialized dict.

    @param JSON-encoded macaroon as dict
    @return the deserialized macaroon object.
    '''
    return Macaroon.deserialize(json.dumps(json_macaroon),
                                json_serializer.JsonSerializer())


def macaroon_to_json_string(macaroon):
    '''Serialize macaroon object to a JSON-encoded string.

    @param macaroon object to be serialized.
    @return a string serialization form of the macaroon.
    '''
    return macaroon.serialize(json_serializer.JsonSerializer())


def _add_base64_padding(b):
    '''Add padding to base64 encoded bytes.

    pymacaroons does not give padded base64 bytes from serialization.

    @param bytes b to be padded.
    @return a padded bytes.
    '''
    return b + b'=' * (-len(b) % 4)


def _remove_base64_padding(b):
    '''Remove padding from base64 encoded bytes.

    pymacaroons does not give padded base64 bytes from serialization.

    @param bytes b to be padded.
    @return a padded bytes.
    '''
    return b.rstrip(b'=')


def b64decode(s):
    '''Base64 decodes a base64-encoded string in URL-safe
    or normal format, with or without padding.
    The argument may be string or bytes.

    @param s bytes decode
    @return bytes decoded
    '''
    # add padding if necessary.
    s = to_bytes(s)
    s = s + b'=' * (-len(s) % 4)
    if '_' or '-' in s:
        return base64.urlsafe_b64decode(s)
    else:
        return base64.b64decode(s)


def raw_urlsafe_b64encode(b):
    '''Base64 encode using URL-safe encoding with padding removed.

    @param b bytes to decode
    @return bytes decoded
    '''
    b = to_bytes(b)
    b = base64.urlsafe_b64encode(b)
    b = b.rstrip(b'=')  # strip padding
    return b


def visit_page_with_browser(visit_url):
    '''Open a browser so the user can validate its identity.

    @param visit_url: where to prove your identity.
    '''
    webbrowser.open(visit_url, new=1)
    print('Opening an authorization web page in your browser.')
    print('If it does not open, please open this URL:\n', visit_url, '\n')


def cookie(
        url,
        name,
        value,
        expires=None):
    '''Return a new Cookie using a slightly more
    friendly API than that provided by six.moves.http_cookiejar
    @param name The cookie name {str}
    @param value The cookie value {str}
    @param url The URL path of the cookie {str}
    @param expires The expiry time of the cookie {datetime}
    '''
    u = urlparse(url)
    domain = u.hostname or u.netloc
    port = str(u.port) if u.port is not None else None
    secure = u.scheme == 'https'
    if expires is not None:
        expires = expires.strftime("%s")
    return http_cookiejar.Cookie(
        version=0,
        name=name,
        value=value,
        port=port,
        port_specified=port is not None,
        domain=domain,
        domain_specified=True,
        domain_initial_dot=False,
        path=u.path,
        path_specified=True,
        secure=secure,
        expires=expires,
        discard=False,
        comment=None,
        comment_url=None,
        rest=None,
        rfc2109=False,
    )