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
|
import importlib
import json
import sys
from oauth2client import client, crypt
from opendc.util import exceptions, parameter_checker
with open(sys.argv[1]) as f:
KEYS = json.load(f)
class Request(object):
"""WebSocket message to REST request mapping."""
def __init__(self, message=None):
""""Initialize a Request from a socket message."""
# Get the Request parameters from the message
if message is None:
return
try:
self.message = message
self.id = message['id']
self.path = message['path']
self.method = message['method']
self.params_body = message['parameters']['body']
self.params_path = message['parameters']['path']
self.params_query = message['parameters']['query']
self.token = message['token']
except KeyError as exception:
raise exceptions.MissingRequestParameterError(exception)
# Parse the path and import the appropriate module
try:
self.path = message['path'].strip('/')
module_base = 'opendc.api.{}.endpoint'
module_path = self.path.replace('/', '.')
self.module = importlib.import_module(module_base.format(module_path))
except ImportError:
raise exceptions.UnimplementedEndpointError('Unimplemented endpoint: {}.'.format(self.path))
# Check the method
if self.method not in ['POST', 'GET', 'PUT', 'PATCH', 'DELETE']:
raise exceptions.UnsupportedMethodError('Non-rest method: {}'.format(self.method))
if not hasattr(self.module, self.method):
raise exceptions.UnsupportedMethodError('Unimplemented method at endpoint {}: {}'.format(
self.path, self.method))
# Verify the user
try:
self.google_id = self._verify_token(self.token)
except crypt.AppIdentityError as e:
raise exceptions.AuthorizationTokenError(e)
def _verify_token(self, token):
"""Return the ID of the signed-in user.
Or throw an Exception if the token is invalid.
"""
try:
idinfo = client.verify_id_token(token, KEYS['OAUTH_CLIENT_ID'])
except Exception as e:
raise crypt.AppIdentityError('Exception caught trying to verify ID token: {}'.format(e))
if idinfo['aud'] != KEYS['OAUTH_CLIENT_ID']:
raise crypt.AppIdentityError('Unrecognized client.')
if idinfo['iss'] not in ['accounts.google.com', 'https://accounts.google.com']:
raise crypt.AppIdentityError('Wrong issuer.')
return idinfo['sub']
def check_required_parameters(self, **kwargs):
"""Raise an error if a parameter is missing or of the wrong type."""
parameter_checker.check(self, **kwargs)
def process(self):
"""Process the Request and return a Response."""
method = getattr(self.module, self.method)
response = method(self)
response.id = self.id
return response
def to_JSON(self):
"""Return a JSON representation of this Request"""
self.message['id'] = 0
self.message['token'] = None
return json.dumps(self.message)
class Response(object):
"""Response to websocket mapping"""
def __init__(self, status_code, status_description, content=None):
"""Initialize a new Response."""
self.status = {'code': status_code, 'description': status_description}
self.content = content
def to_JSON(self):
""""Return a JSON representation of this Response"""
data = {'id': self.id, 'status': self.status}
if self.content is not None:
data['content'] = self.content
return json.dumps(data)
|