28
30
from base64 import b64decode
29
from restish import guard, http, resource
30
31
from zope.component import getUtility
32
33
from mailman.config import config
33
34
from mailman.core.constants import system_preferences
34
35
from mailman.core.system import system
35
36
from mailman.interfaces.listmanager import IListManager
36
from mailman.interfaces.styles import IStyleManager
37
37
from mailman.rest.addresses import AllAddresses, AnAddress
38
38
from mailman.rest.domains import ADomain, AllDomains
39
from mailman.rest.helpers import etag, path_to
40
from mailman.rest.lists import AList, AllLists
39
from mailman.rest.helpers import (
40
BadRequest, NotFound, child, etag, okay, path_to)
41
from mailman.rest.lists import AList, AllLists, Styles
41
42
from mailman.rest.members import AMember, AllMembers, FindMembers
42
43
from mailman.rest.preferences import ReadOnlyPreferences
43
44
from mailman.rest.templates import TemplateFinder
48
def webservice_auth_checker(request, obj):
49
auth = request.environ.get('HTTP_AUTHORIZATION', '')
50
if auth.startswith('Basic '):
51
credentials = b64decode(auth[6:])
52
username, password = credentials.split(':', 1)
53
if (username != config.webservice.admin_user or
54
password != config.webservice.admin_pass):
56
raise guard.GuardError(b'User is not authorized for the REST API')
58
raise guard.GuardError(b'The REST API requires authentication')
61
class Root(resource.Resource):
62
50
"""The RESTful root resource.
64
52
At the root of the tree are the API version numbers. Everything else
67
55
always be the case though.
70
@resource.child(config.webservice.api_version)
71
@guard.guard(webservice_auth_checker)
58
@child(config.webservice.api_version)
72
59
def api_version(self, request, segments):
60
# We have to do this here instead of in a @falcon.before() handler
61
# because those handlers are not compatible with our custom traversal
62
# logic. Specifically, falcon's before/after handlers will call the
63
# responder, but the method we're wrapping isn't a responder, it's a
64
# child traversal method. There's no way to cause the thing that
65
# calls the before hook to follow through with the child traversal in
66
# the case where no error is raised.
67
if request.auth is None:
68
raise falcon.HTTPUnauthorized(
70
b'The REST API requires authentication')
71
if request.auth.startswith('Basic '):
72
credentials = b64decode(request.auth[6:])
73
username, password = credentials.split(':', 1)
74
if (username != config.webservice.admin_user or
75
password != config.webservice.admin_pass):
77
raise falcon.HTTPUnauthorized(
79
b'User is not authorized for the REST API')
76
class TopLevel(resource.Resource):
84
def on_get(self, request, response):
87
mailman_version=system.mailman_version,
88
python_version=system.python_version,
89
self_link=path_to('system'),
91
okay(response, etag(resource))
77
95
"""Top level collections and entries."""
80
98
def system(self, request, segments):
81
99
"""/<api>/system"""
82
100
if len(segments) == 0:
84
mailman_version=system.mailman_version,
85
python_version=system.python_version,
86
self_link=path_to('system'),
88
102
elif len(segments) > 1:
89
return http.bad_request()
103
return BadRequest(), []
90
104
elif segments[0] == 'preferences':
91
105
return ReadOnlyPreferences(system_preferences, 'system'), []
93
return http.bad_request()
94
return http.ok([], etag(resource))
107
return NotFound(), []
97
110
def addresses(self, request, segments):
98
111
"""/<api>/addresses
99
112
/<api>/addresses/<email>
124
137
if len(segments) == 0:
125
138
return AllLists()
126
139
elif len(segments) == 1 and segments[0] == 'styles':
127
manager = getUtility(IStyleManager)
128
style_names = sorted(style.name for style in manager.styles)
129
resource = dict(style_names=style_names,
130
default=config.styles.default)
131
return http.ok([], etag(resource))
133
142
# list-id is preferred, but for backward compatibility,
134
143
# fqdn_listname is also accepted.
135
144
list_identifier = segments.pop(0)
136
145
return AList(list_identifier), segments
139
148
def members(self, request, segments):
140
149
"""/<api>/members"""
141
150
if len(segments) == 0: