Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
.vscode/settings.json
uplink-c/
libuplinkc.so
secret.txt
__pycache__/
20 changes: 19 additions & 1 deletion docs/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,9 @@ StorjException is further sub-categorized into various error specific classes, T
UploadDoneError
CancelledError
InvalidHandleError

StorageLimitExceededError
SegmentsLimitExceededError
PermissionDeniedError

### InternalError

Expand Down Expand Up @@ -435,13 +437,29 @@ UploadDoneError is raised when either Abort or Commit has already been called.

InvalidHandleError is raised when object handle passes is either invalid or already freed.

### StorageLimitExceededError

StorageLimitExceededError is raised when allowed storage limit exceeded.

### SegmentsLimitExceededError

SegmentsLimitExceededError is raised when allowed segments limit exceeded.

### PermissionDeniedError

PermissionDeniedError is raised when permission is denied.

## Constants

ERROR_INTERNAL = 0x02
ERROR_CANCELED = 0x03
ERROR_INVALID_HANDLE = 0x04
ERROR_TOO_MANY_REQUESTS = 0x05
ERROR_BANDWIDTH_LIMIT_EXCEEDED = 0x06
ERROR_STORAGE_LIMIT_EXCEEDED = 0x07
ERROR_SEGMENTS_LIMIT_EXCEEDED = 0x08
ERROR_PERMISSION_DENIED = 0x09

# Types, Errors, and Constants

## Types
Expand Down
39 changes: 39 additions & 0 deletions test/test_data/project_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# pylint: disable=missing-docstring
import unittest
from uplink_python.errors import BucketAlreadyExistError
from uplink_python.module_classes import Permission, SharePrefix

from .helper import TestPy

Expand All @@ -15,5 +17,42 @@ def test1_open_project(self):
self.assertIsNotNone(project, "open_project failed")


def test2_revoke_access(self):
# sanity check current credentials
project = self.access.open_project()
self.assertIsNotNone(project, "open_project failed")
try:
_ = project.create_bucket("alpha")
except BucketAlreadyExistError:
pass
test_access_availability(project, "1")

# create derived credentials to be revoked
permissions = Permission(allow_list=True, allow_download=True, allow_upload=True, allow_delete=True)
shared_prefix = [SharePrefix(bucket="alpha", prefix="")]
access = self.access.share(permissions, shared_prefix)
self.assertTrue(access.access.contents._handle != 0, "got empty access")
self.assertIsNotNone(access, "access_share failed")

# sanity check derived credentials
project2 = access.open_project()
self.assertIsNotNone(project2, "open_project2 failed")
test_access_availability(project2, "2")

# revoke derived credentials
project.revoke_access(access)

# expect derived credentials to fail
# this test is non-deterministic due to credential caching
# it can be reasonable proven with a time.sleep() however
#with self.assertRaises(PermissionDeniedError) as context:
# test_access_availability(project2, "3")

def test_access_availability(project, num: str):
data_bytes = bytes("!" * 1024 , 'utf-8')
upload = project.upload_object("alpha", "test_object_" + num)
_ = upload.write(data_bytes, len(data_bytes))
upload.commit()

if __name__ == '__main__':
unittest.main()
67 changes: 66 additions & 1 deletion uplink_python/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
ERROR_INVALID_HANDLE = 0x04
ERROR_TOO_MANY_REQUESTS = 0x05
ERROR_BANDWIDTH_LIMIT_EXCEEDED = 0x06
ERROR_STORAGE_LIMIT_EXCEEDED = 0x07
ERROR_SEGMENTS_LIMIT_EXCEEDED = 0x08
ERROR_PERMISSION_DENIED = 0x09

ERROR_BUCKET_NAME_INVALID = 0x10
ERROR_BUCKET_ALREADY_EXISTS = 0x11
Expand All @@ -14,6 +17,10 @@
ERROR_OBJECT_KEY_INVALID = 0x20
ERROR_OBJECT_NOT_FOUND = 0x21
ERROR_UPLOAD_DONE = 0x22

ERROR_AUTH_DIAL_FAILED = 0x30
ERROR_REGISTER_ACCESS_FAILED = 0x31

ERROR_LIBUPLINK_SO_NOT_FOUND = 0x9999
"""_Error defines"""

Expand Down Expand Up @@ -92,6 +99,38 @@ def __init__(self, details):
super().__init__("bandwidth limit exceeded", ERROR_BANDWIDTH_LIMIT_EXCEEDED, details)


class StorageLimitExceededError(StorjException):
"""Exception raised if allowed storage limit exceeded.

Attributes:
details -- error message from uplink-c
"""

def __init__(self, details):
super().__init__("storage limit exceeded", ERROR_STORAGE_LIMIT_EXCEEDED, details)

class SegmentsLimitExceededError(StorjException):
"""Exception raised if allowed segments limit exceeded.

Attributes:
details -- error message from uplink-c
"""

def __init__(self, details):
super().__init__("segments limit exceeded", ERROR_SEGMENTS_LIMIT_EXCEEDED, details)


class PermissionDeniedError(StorjException):
"""Exception raised if permission denied.

Attributes:
details -- error message from uplink-c
"""

def __init__(self, details):
super().__init__("permission denied", ERROR_PERMISSION_DENIED, details)


class BucketNameInvalidError(StorjException):
"""Exception raised if bucket name is invalid.

Expand Down Expand Up @@ -169,6 +208,27 @@ def __init__(self, details):
super().__init__("upload completed", ERROR_UPLOAD_DONE, details)


class AuthDialFailedError(StorjException):
"""Exception raised if failure to dial the Auth Service.

Attributes:
details -- error message from uplink-c
"""

def __init__(self, details):
super().__init__("Auth dial failed", ERROR_AUTH_DIAL_FAILED, details)

class RegisterAccessFailedError(StorjException):
"""Exception raised if failure to register access grant with Auth Service.

Attributes:
details -- error message from uplink-c
"""

def __init__(self, details):
super().__init__("register accees failed", ERROR_REGISTER_ACCESS_FAILED, details)


class LibUplinkSoError(StorjException):
"""Exception raised if reason is unknown.

Expand All @@ -191,12 +251,17 @@ def _storj_exception(code, details):
ERROR_INVALID_HANDLE: InvalidHandleError,
ERROR_TOO_MANY_REQUESTS: TooManyRequestsError,
ERROR_BANDWIDTH_LIMIT_EXCEEDED: BandwidthLimitExceededError,
ERROR_STORAGE_LIMIT_EXCEEDED:StorageLimitExceededError,
ERROR_SEGMENTS_LIMIT_EXCEEDED:SegmentsLimitExceededError,
ERROR_PERMISSION_DENIED:PermissionDeniedError,
ERROR_BUCKET_NAME_INVALID: BucketNameInvalidError,
ERROR_BUCKET_ALREADY_EXISTS: BucketAlreadyExistError,
ERROR_BUCKET_NOT_EMPTY: BucketNotEmptyError,
ERROR_BUCKET_NOT_FOUND: BucketNotFoundError,
ERROR_OBJECT_KEY_INVALID: ObjectKeyInvalidError,
ERROR_OBJECT_NOT_FOUND: ObjectNotFoundError,
ERROR_UPLOAD_DONE: UploadDoneError
ERROR_UPLOAD_DONE: UploadDoneError,
ERROR_AUTH_DIAL_FAILED:AuthDialFailedError,
ERROR_REGISTER_ACCESS_FAILED:RegisterAccessFailedError,
}
return switcher.get(code, StorjException)(details=details)
30 changes: 28 additions & 2 deletions uplink_python/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@
from uplink_python.module_def import _BucketStruct, _ObjectStruct, _ListObjectsOptionsStruct,\
_ObjectResult, _ListBucketsOptionsStruct, _UploadOptionsStruct, _DownloadOptionsStruct,\
_ProjectStruct, _BucketResult, _BucketIterator, _ObjectIterator, _DownloadResult,\
_UploadResult, _Error
_UploadResult, _Error, _AccessStruct
from uplink_python.upload import Upload
from uplink_python.download import Download
from uplink_python.errors import _storj_exception


class Project:
"""
Project provides access to managing buckets and objects.
Expand Down Expand Up @@ -391,6 +390,33 @@ def close(self):
raise _storj_exception(error.contents.code,
error.contents.message.decode("utf-8"))

def revoke_access(self, access):
"""
revoke_access revokes the API key embedded in the provided access grant.

Returns
-------
None
"""
#
# declare types of arguments and response of the corresponding golang function
self.uplink.m_libuplink.uplink_revoke_access.argtypes =\
[ctypes.POINTER(_ProjectStruct), ctypes.POINTER(_AccessStruct)]
self.uplink.m_libuplink.uplink_revoke_access.restype = ctypes.POINTER(_Error)

# get uploader by calling the exported golang function
error = self.uplink.m_libuplink.uplink_revoke_access(self.project, access.access)
has_err = bool(error)
if bool(error):
err_code = error.contents.code
err_msg = error.contents.message.decode("utf-8")
self.uplink.m_libuplink.uplink_free_error.argtypes = [ctypes.POINTER(_Error)]
self.uplink.m_libuplink.uplink_free_error(error)
if has_err:
raise _storj_exception(err_code, err_msg)

return None

def upload_object(self, bucket_name: str, storj_path: str,
upload_options: UploadOptions = None):
"""
Expand Down