Revision 4a105ce2
b/contrib/migrate-db | ||
---|---|---|
168 | 168 |
if public: |
169 | 169 |
self.backend.permissions.public_set( |
170 | 170 |
object, |
171 |
self.backend.public_url_min_length,
|
|
171 |
self.backend.public_url_security,
|
|
172 | 172 |
self.backend.public_url_alphabet |
173 | 173 |
) |
174 | 174 |
#set object's permissions |
b/snf-pithos-app/README | ||
---|---|---|
57 | 57 |
PITHOS_USE_QUOTAHOLDER True Enable quotaholder |
58 | 58 |
PITHOS_QUOTAHOLDER_URL '' Quotaholder URL |
59 | 59 |
PITHOS_QUOTAHOLDER_TOKEN '' Quotaholder token |
60 |
PITHOS_PUBLIC_URL_MIN_LENGTH 8 Public URL minimun length
|
|
61 |
PITHOS_PUBLIC_URL_ALPHABET '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' Public URL alphabet
|
|
60 |
PITHOS_PUBLIC_URL_SECURITY 16 How many random bytes to use for constructing the URL of Pithos public files
|
|
61 |
PITHOS_PUBLIC_URL_ALPHABET '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' The alphabet to use for constructing the URL of Pithos public files
|
|
62 | 62 |
=============================== ================================================================ ============================================================ |
63 | 63 |
|
64 | 64 |
To update checksums asynchronously, enable the queue, install snf-pithos-tools and use ``pithos-dispatcher``:: |
b/snf-pithos-app/conf/20-snf-pithos-app-settings.conf | ||
---|---|---|
56 | 56 |
# |
57 | 57 |
#PITHOS_QUOTAHOLDER_POOLSIZE = 200 |
58 | 58 |
# |
59 |
# Set public url length |
|
60 |
#PITHOS_PUBLIC_URL_MIN_LENGTH = 8 |
|
59 |
# How many random bytes to use for constructing the URL of Pithos public files. |
|
60 |
# Lower values mean accidental reuse of (discarded) URLs is more probable. |
|
61 |
# Note: the active public URLs will always be unique. |
|
62 |
# Only the old and discarded URLs can ever be reused. |
|
63 |
# Higher values mean more safety and longer URLs |
|
64 |
# |
|
65 |
#PITHOS_PUBLIC_URL_SECURITY = 16 |
b/snf-pithos-app/pithos/api/settings.py | ||
---|---|---|
66 | 66 |
QUOTAHOLDER_TOKEN = getattr(settings, 'PITHOS_QUOTAHOLDER_TOKEN', '') |
67 | 67 |
QUOTAHOLDER_POOLSIZE = getattr(settings, 'PITHOS_QUOTAHOLDER_POOLSIZE', 200) |
68 | 68 |
|
69 |
# Set public url length and alphabet |
|
70 |
PUBLIC_URL_MIN_LENGTH = getattr(settings, 'PITHOS_PUBLIC_URL_MIN_LENGTH', 8) |
|
69 |
# Set how many random bytes to use for constructing the URL of Pithos public files |
|
70 |
PUBLIC_URL_SECURITY = getattr(settings, 'PITHOS_PUBLIC_URL_SECURITY', 16) |
|
71 |
# Set the alphabet to use for constructing the URL of Pithos public files |
|
71 | 72 |
PUBLIC_URL_ALPHABET = getattr( |
72 | 73 |
settings, |
73 | 74 |
'PITHOS_PUBLIC_URL_ALPHABET', |
b/snf-pithos-app/pithos/api/swiss_army/__init__.py | ||
---|---|---|
196 | 196 |
fullpath = '/'.join([dest_account, dest_container, dest_name]) |
197 | 197 |
self.backend.permissions.public_set( |
198 | 198 |
fullpath, |
199 |
self.backend.public_url_min_length,
|
|
199 |
self.backend.public_url_security,
|
|
200 | 200 |
self.backend.public_url_alphabet |
201 | 201 |
) |
202 | 202 |
|
b/snf-pithos-app/pithos/api/tests.py | ||
---|---|---|
77 | 77 |
account, account, container, object |
78 | 78 |
) |
79 | 79 |
self.assertTrue(public != None) |
80 |
self.assertTrue(len(public) >= settings.PUBLIC_URL_MIN_LENGTH)
|
|
80 |
self.assertTrue(len(public) >= settings.PUBLIC_URL_SECURITY)
|
|
81 | 81 |
self.assertTrue(set(public) <= set(settings.PUBLIC_URL_ALPHABET)) |
82 | 82 |
self.assertEqual( |
83 | 83 |
self.backend.get_public('$$account$$', public), |
... | ... | |
103 | 103 |
|
104 | 104 |
self.backend.permissions.public_set( |
105 | 105 |
'account/container/object', |
106 |
self.backend.public_url_min_length,
|
|
106 |
self.backend.public_url_security,
|
|
107 | 107 |
self.backend.public_url_alphabet |
108 | 108 |
) |
109 | 109 |
self.assert_public_object('account', 'container', 'object') |
... | ... | |
120 | 120 |
) |
121 | 121 |
self.backend.permissions.public_set( |
122 | 122 |
'account/container/object', |
123 |
self.backend.public_url_min_length,
|
|
123 |
self.backend.public_url_security,
|
|
124 | 124 |
self.backend.public_url_alphabet |
125 | 125 |
) |
126 | 126 |
public = self.assert_public_object('account', 'container', 'object') |
127 | 127 |
|
128 | 128 |
self.backend.permissions.public_set( |
129 | 129 |
'account/container/object', |
130 |
self.backend.public_url_min_length,
|
|
130 |
self.backend.public_url_security,
|
|
131 | 131 |
self.backend.public_url_alphabet |
132 | 132 |
) |
133 | 133 |
public2 = self.assert_public_object('account', 'container', 'object') |
... | ... | |
146 | 146 |
) |
147 | 147 |
self.backend.permissions.public_set( |
148 | 148 |
'account/container/object', |
149 |
self.backend.public_url_min_length,
|
|
149 |
self.backend.public_url_security,
|
|
150 | 150 |
self.backend.public_url_alphabet |
151 | 151 |
) |
152 | 152 |
public = self.assert_public_object('account', 'container', 'object') |
... | ... | |
156 | 156 |
|
157 | 157 |
self.backend.permissions.public_set( |
158 | 158 |
'account/container/object', |
159 |
self.backend.public_url_min_length,
|
|
159 |
self.backend.public_url_security,
|
|
160 | 160 |
self.backend.public_url_alphabet |
161 | 161 |
) |
162 | 162 |
public3 = self.assert_public_object('account', 'container', 'object') |
... | ... | |
225 | 225 |
|
226 | 226 |
self.backend.permissions.public_set( |
227 | 227 |
'account/container/object', |
228 |
self.backend.public_url_min_length,
|
|
228 |
self.backend.public_url_security,
|
|
229 | 229 |
self.backend.public_url_alphabet |
230 | 230 |
) |
231 | 231 |
self.assert_public_object('account', 'container', 'object') |
... | ... | |
253 | 253 |
|
254 | 254 |
self.backend.permissions.public_set( |
255 | 255 |
'account/container/object', |
256 |
self.backend.public_url_min_length,
|
|
256 |
self.backend.public_url_security,
|
|
257 | 257 |
self.backend.public_url_alphabet |
258 | 258 |
) |
259 | 259 |
public = self.assert_public_object('account', 'container', 'object') |
b/snf-pithos-app/pithos/api/util.py | ||
---|---|---|
68 | 68 |
COOKIE_NAME, USER_CATALOG_URL, |
69 | 69 |
RADOS_STORAGE, RADOS_POOL_BLOCKS, |
70 | 70 |
RADOS_POOL_MAPS, TRANSLATE_UUIDS, |
71 |
PUBLIC_URL_MIN_LENGTH,
|
|
71 |
PUBLIC_URL_SECURITY,
|
|
72 | 72 |
PUBLIC_URL_ALPHABET) |
73 | 73 |
from pithos.backends import connect_backend |
74 | 74 |
from pithos.backends.base import (NotAllowedError, QuotaError, ItemNotExists, |
... | ... | |
985 | 985 |
quotaholder_client_poolsize=QUOTAHOLDER_POOLSIZE, |
986 | 986 |
free_versioning=BACKEND_FREE_VERSIONING, |
987 | 987 |
block_params=BLOCK_PARAMS, |
988 |
public_url_min_length=PUBLIC_URL_MIN_LENGTH,
|
|
988 |
public_url_security=PUBLIC_URL_SECURITY,
|
|
989 | 989 |
public_url_alphabet=PUBLIC_URL_ALPHABET) |
990 | 990 |
|
991 | 991 |
def get_backend(): |
b/snf-pithos-backend/pithos/backends/lib/sqlalchemy/public.py | ||
---|---|---|
37 | 37 |
from sqlalchemy.schema import Index |
38 | 38 |
from sqlalchemy.exc import NoSuchTableError |
39 | 39 |
|
40 |
from pithos.backends.random_word import get_word |
|
40 |
from pithos.backends.random_word import get_random_word |
|
41 |
|
|
42 |
import logging |
|
43 |
|
|
44 |
logger = logging.getLogger(__name__) |
|
41 | 45 |
|
42 | 46 |
def create_tables(engine): |
43 | 47 |
metadata = MetaData() |
... | ... | |
68 | 72 |
tables = create_tables(self.engine) |
69 | 73 |
map(lambda t: self.__setattr__(t.name, t), tables) |
70 | 74 |
|
71 |
def get_unique_url(self, serial, public_url_min_length, public_url_alphabet):
|
|
72 |
l = public_url_min_length
|
|
75 |
def get_unique_url(self, public_security, public_url_alphabet):
|
|
76 |
l = public_security
|
|
73 | 77 |
while 1: |
74 |
candidate = get_word(serial, length=l, alphabet=public_url_alphabet)
|
|
78 |
candidate = get_random_word(length=l, alphabet=public_url_alphabet)
|
|
75 | 79 |
if self.public_path(candidate) is None: |
76 | 80 |
return candidate |
77 | 81 |
l +=1 |
78 | 82 |
|
79 |
def public_set(self, path, public_url_min_length, public_url_alphabet):
|
|
83 |
def public_set(self, path, public_security, public_url_alphabet):
|
|
80 | 84 |
s = select([self.public.c.public_id]) |
81 | 85 |
s = s.where(self.public.c.path == path) |
82 | 86 |
r = self.conn.execute(s) |
... | ... | |
84 | 88 |
r.close() |
85 | 89 |
|
86 | 90 |
if not row: |
91 |
url = self.get_unique_url( |
|
92 |
public_security, public_url_alphabet |
|
93 |
) |
|
87 | 94 |
s = self.public.insert() |
88 |
s = s.values(path=path, active=True) |
|
95 |
s = s.values(path=path, active=True, url=url)
|
|
89 | 96 |
r = self.conn.execute(s) |
90 |
serial = r.inserted_primary_key[0] |
|
91 | 97 |
r.close() |
92 |
|
|
93 |
url = self.get_unique_url( |
|
94 |
serial, public_url_min_length, public_url_alphabet |
|
95 |
) |
|
96 |
s = self.public.update().where(self.public.c.public_id == serial) |
|
97 |
s = s.values(url=url) |
|
98 |
self.conn.execute(s).close() |
|
98 |
logger.info('Public url: %s set for path: %s' % (url, path)) |
|
99 | 99 |
|
100 | 100 |
def public_unset(self, path): |
101 | 101 |
s = self.public.delete() |
102 | 102 |
s = s.where(self.public.c.path == path) |
103 | 103 |
self.conn.execute(s).close() |
104 |
logger.info('Public url unset for path: %s' % (path)) |
|
104 | 105 |
|
105 | 106 |
def public_unset_bulk(self, paths): |
106 | 107 |
if not paths: |
b/snf-pithos-backend/pithos/backends/lib/sqlite/public.py | ||
---|---|---|
33 | 33 |
|
34 | 34 |
from dbworker import DBWorker |
35 | 35 |
|
36 |
from pithos.backends.random_word import get_word |
|
36 |
from pithos.backends.random_word import get_random_word |
|
37 |
|
|
38 |
import logging |
|
39 |
|
|
40 |
logger = logging.getLogger(__name__) |
|
37 | 41 |
|
38 | 42 |
class Public(DBWorker): |
39 | 43 |
"""Paths can be marked as public.""" |
... | ... | |
52 | 56 |
execute(""" create unique index if not exists idx_public_url |
53 | 57 |
on public(url) """) |
54 | 58 |
|
55 |
def get_unique_url(self, serial, public_url_min_length, public_url_alphabet):
|
|
56 |
l = public_url_min_length
|
|
59 |
def get_unique_url(self, public_url_security, public_url_alphabet):
|
|
60 |
l = public_url_security
|
|
57 | 61 |
while 1: |
58 |
candidate = get_word(serial, length=l, alphabet=public_url_alphabet)
|
|
62 |
candidate = get_random_word(length=l, alphabet=public_url_alphabet)
|
|
59 | 63 |
if self.public_path(candidate) is None: |
60 | 64 |
return candidate |
61 | 65 |
l +=1 |
62 | 66 |
|
63 |
def public_set(self, path, public_url_min_length, public_url_alphabet):
|
|
67 |
def public_set(self, path, public_url_security, public_url_alphabet):
|
|
64 | 68 |
q = "select public_id from public where path = ?" |
65 | 69 |
self.execute(q, (path,)) |
66 | 70 |
row = self.fetchone() |
67 | 71 |
|
68 | 72 |
if not row: |
69 |
q = "insert into public(path, active) values(?, ?)" |
|
70 |
serial = self.execute(q, (path, active)).lastrowid |
|
71 | 73 |
url = self.get_unique_url( |
72 |
serial, public_url_min_length, public_url_alphabet
|
|
74 |
public_url_security, public_url_alphabet
|
|
73 | 75 |
) |
74 |
q = "update public set url=url where public_id = ?" |
|
75 |
self.execute(q, (serial,)) |
|
76 |
q = "insert into public(path, active, url) values(?, 1, ?)" |
|
77 |
self.execute(q, (path, url)) |
|
78 |
logger.info('Public url: %s set for path: %s' % (url, path)) |
|
76 | 79 |
|
77 | 80 |
def public_unset(self, path): |
78 | 81 |
q = "delete from public where path = ?" |
79 | 82 |
self.execute(q, (path,)) |
83 |
logger.info('Public url unset for path: %s' % (path)) |
|
80 | 84 |
|
81 | 85 |
def public_unset_bulk(self, paths): |
82 | 86 |
placeholders = ','.join('?' for path in paths) |
83 |
q = "delete from public where path in (%s)" |
|
87 |
q = "delete from public where path in (%s)" % placeholders
|
|
84 | 88 |
self.execute(q, paths) |
85 | 89 |
|
86 | 90 |
def public_get(self, path): |
b/snf-pithos-backend/pithos/backends/modular.py | ||
---|---|---|
84 | 84 |
DEFAULT_BLOCK_PARAMS = { 'mappool': None, 'blockpool': None } |
85 | 85 |
#DEFAULT_QUEUE_HOSTS = '[amqp://guest:guest@localhost:5672]' |
86 | 86 |
#DEFAULT_QUEUE_EXCHANGE = 'pithos' |
87 |
DEFAULT_ALPHABET = ('0123456789' |
|
88 |
'abcdefghijklmnopqrstuvwxyz' |
|
89 |
'ABCDEFGHIJKLMNOPQRSTUVWXYZ') |
|
90 |
DEFAULT_MIN_LENGTH = 8
|
|
87 |
DEFAULT_PUBLIC_URL_ALPHABET = ('0123456789'
|
|
88 |
'abcdefghijklmnopqrstuvwxyz'
|
|
89 |
'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
|
90 |
DEFAULT_PUBLIC_URL_SECURITY = 8
|
|
91 | 91 |
|
92 | 92 |
QUEUE_MESSAGE_KEY_PREFIX = 'pithos.%s' |
93 | 93 |
QUEUE_CLIENT_ID = 'pithos' |
... | ... | |
153 | 153 |
quotaholder_url=None, quotaholder_token=None, |
154 | 154 |
quotaholder_client_poolsize=None, |
155 | 155 |
free_versioning=True, block_params=None, |
156 |
public_url_min_length=None,
|
|
156 |
public_url_security=None,
|
|
157 | 157 |
public_url_alphabet=None): |
158 | 158 |
db_module = db_module or DEFAULT_DB_MODULE |
159 | 159 |
db_connection = db_connection or DEFAULT_DB_CONNECTION |
... | ... | |
167 | 167 |
#queue_hosts = queue_hosts or DEFAULT_QUEUE_HOSTS |
168 | 168 |
#queue_exchange = queue_exchange or DEFAULT_QUEUE_EXCHANGE |
169 | 169 |
|
170 |
self.public_url_min_length = public_url_min_length or DEFAULT_MIN_LENGTH
|
|
171 |
self.public_url_alphabet = public_url_alphabet or DEFAULT_ALPHABET |
|
170 |
self.public_url_security = public_url_security or DEFAULT_PUBLIC_URL_SECURITY
|
|
171 |
self.public_url_alphabet = public_url_alphabet or DEFAULT_PUBLIC_URL_ALPHABET
|
|
172 | 172 |
|
173 | 173 |
self.hash_algorithm = 'sha256' |
174 | 174 |
self.block_size = 4 * 1024 * 1024 # 4MB |
... | ... | |
838 | 838 |
self.permissions.public_unset(path) |
839 | 839 |
else: |
840 | 840 |
self.permissions.public_set( |
841 |
path, self.public_url_min_length, self.public_url_alphabet
|
|
841 |
path, self.public_url_security, self.public_url_alphabet
|
|
842 | 842 |
) |
843 | 843 |
|
844 | 844 |
@backend_method |
b/snf-pithos-backend/pithos/backends/random_word.py | ||
---|---|---|
31 | 31 |
# interpreted as representing official policies, either expressed |
32 | 32 |
# or implied, of GRNET S.A. |
33 | 33 |
|
34 |
DEFAULT_ALPHABET = ('0123456789' |
|
35 |
'abcdefghijklmnopqrstuvwxyz' |
|
36 |
'ABCDEFGHIJKLMNOPQRSTUVWXYZ') |
|
37 |
DEFAULT_MIN_LENGTH = 8 |
|
34 |
import random |
|
38 | 35 |
|
39 |
from random import randrange |
|
40 |
from math import log |
|
36 |
getrandbits = random.SystemRandom().getrandbits |
|
41 | 37 |
|
42 |
def get_random_word(length=DEFAULT_MIN_LENGTH, alphabet=DEFAULT_ALPHABET): |
|
43 |
alphabet_length = len(alphabet) |
|
44 |
word = ''.join(alphabet[randrange(alphabet_length)] |
|
45 |
for _ in xrange(length)) |
|
46 |
return word |
|
38 |
DEFAULT_ALPHABET = ("0123456789" |
|
39 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|
40 |
"abcdefghijklmnopqrstuvwxyz") |
|
47 | 41 |
|
48 |
def encode_serial(serial, alphabet=DEFAULT_ALPHABET): |
|
49 |
i = 0 |
|
42 |
def get_random_word(length, alphabet=DEFAULT_ALPHABET): |
|
43 |
remainder = getrandbits(length * 8) |
|
44 |
return encode_word(remainder, alphabet=alphabet) |
|
45 |
|
|
46 |
def encode_word(number, alphabet=DEFAULT_ALPHABET): |
|
50 | 47 |
base = len(alphabet) |
51 |
quotient = int(serial) |
|
52 | 48 |
digits = [] |
53 | 49 |
append = digits.append |
54 |
while quotient > 0: |
|
50 |
quotient = number |
|
51 |
while True: |
|
55 | 52 |
quotient, remainder = divmod(quotient, base) |
56 | 53 |
append(alphabet[remainder]) |
57 |
word = ''.join(reversed(digits))
|
|
58 |
return word
|
|
54 |
if quotient <= 0:
|
|
55 |
break
|
|
59 | 56 |
|
60 |
def get_word(serial, length=DEFAULT_MIN_LENGTH, alphabet=DEFAULT_ALPHABET): |
|
61 |
word = encode_serial(serial, alphabet) |
|
62 |
word += get_random_word(length, alphabet) |
|
63 |
return word |
|
57 |
return ''.join(digits) |
b/snf-pithos-backend/pithos/backends/util.py | ||
---|---|---|
49 | 49 |
quotaholder_url=None, quotaholder_token=None, |
50 | 50 |
quotaholder_client_poolsize=None, |
51 | 51 |
block_params=None, |
52 |
public_url_min_length=None,
|
|
52 |
public_url_security=None,
|
|
53 | 53 |
public_url_alphabet=None): |
54 | 54 |
super(PithosBackendPool, self).__init__(size=size) |
55 | 55 |
self.db_module = db_module |
... | ... | |
66 | 66 |
self.quotaholder_token = quotaholder_token |
67 | 67 |
self.quotaholder_client_poolsize = quotaholder_client_poolsize |
68 | 68 |
self.free_versioning = free_versioning |
69 |
self.public_url_min_length=public_url_min_length
|
|
69 |
self.public_url_security=public_url_security
|
|
70 | 70 |
self.public_url_alphabet=public_url_alphabet |
71 | 71 |
|
72 | 72 |
def _pool_create(self): |
... | ... | |
85 | 85 |
quotaholder_token=self.quotaholder_token, |
86 | 86 |
quotaholder_client_poolsize=self.quotaholder_client_poolsize, |
87 | 87 |
free_versioning=self.free_versioning, |
88 |
public_url_min_length=self.public_url_min_length,
|
|
88 |
public_url_security=self.public_url_security,
|
|
89 | 89 |
public_url_alphabet=self.public_url_alphabet) |
90 | 90 |
|
91 | 91 |
backend._real_close = backend.close |
Also available in: Unified diff