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
|
# -*- coding: utf-8 -*-
"""
Created on Tue Mar 5 18:46:38 2013
@author: drebs
"""
try:
import simplejson as json
except ImportError:
import json # noqa
from u1db import errors
from u1db.remote import http_database
#-----------------------------------------------------------------------------
# Soledad shared database
#-----------------------------------------------------------------------------
class NoTokenForAuth(Exception):
"""
No token was found for token-based authentication.
"""
class Unauthorized(Exception):
"""
User does not have authorization to perform task.
"""
class SoledadSharedDatabase(http_database.HTTPDatabase):
"""
This is a shared HTTP database that holds users' encrypted keys.
An authorization token is attached to every request other than
get_doc_unauth, which has the purpose of retrieving encrypted content from
the shared database without the need to associate user information with
the request.
"""
# TODO: prevent client from messing with the shared DB.
# TODO: define and document API.
@staticmethod
def open_database(url, create, token=None):
"""
Open a Soledad shared database.
"""
db = SoledadSharedDatabase(url, token=token)
db.open(create)
return db
@staticmethod
def delete_database(url):
"""
Dummy method that prevents from deleting shared database.
"""
raise Unauthorized("Can't delete shared database.")
def __init__(self, url, document_factory=None, creds=None, token=None):
"""
Initialize database with auth token and encryption powers.
"""
self._token = token
super(SoledadSharedDatabase, self).__init__(url, document_factory,
creds)
def _request(self, method, url_parts, params=None, body=None,
content_type=None, auth=True):
"""
Perform token-based http request.
"""
# add the auth-token as a request parameter
if auth:
if not self._token:
raise NoTokenForAuth()
if not params:
params = {}
params['auth_token'] = self._token
return super(SoledadSharedDatabase, self)._request(
method, url_parts,
params,
body,
content_type)
def _request_json(self, method, url_parts, params=None, body=None,
content_type=None, auth=True):
"""
Perform token-based http request.
"""
# allow for token-authenticated requests.
res, headers = self._request(method, url_parts,
params=params, body=body,
content_type=content_type, auth=auth)
return json.loads(res), headers
def get_doc_unauth(self, doc_id):
"""
Modified method to allow for unauth request.
"""
try:
res, headers = self._request(
'GET', ['doc', doc_id], {"include_deleted": False},
auth=False)
except errors.DocumentDoesNotExist:
return None
except errors.HTTPError, e:
if (e.status == http_database.DOCUMENT_DELETED_STATUS and
'x-u1db-rev' in e.headers):
res = None
headers = e.headers
else:
raise
doc_rev = headers['x-u1db-rev']
has_conflicts = json.loads(headers['x-u1db-has-conflicts'])
doc = self._factory(doc_id, doc_rev, res)
doc.has_conflicts = has_conflicts
return doc
|