def from_data(data): """Return a DebitNote that has been extracted from the passed json-decoded dictionary Args: data (dict): Dictionary from which to create object Returns: DebitNote: Created from dictionary """ d = DebitNote() if (data and len(data) > 0): from Acquire.Accounting import Transaction as _Transaction from Acquire.Identity import Authorisation as _Authorisation from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime d._transaction = _Transaction.from_data(data["transaction"]) d._account_uid = data["account_uid"] d._authorisation = _Authorisation.from_data(data["authorisation"]) d._is_provisional = data["is_provisional"] d._datetime = _string_to_datetime(data["datetime"]) d._uid = data["uid"] if d._is_provisional: d._receipt_by = _string_to_datetime(data["receipt_by"]) return d
def from_data(data): """Construct and return a new CreditNote from the passed json-decoded dictionary Args: data (dict): JSON serialised dictionary of object Returns: CreditNote: CreditNote created from JSON data """ note = CreditNote() if (data and len(data) > 0): from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime from Acquire.Accounting import create_decimal as _create_decimal note._account_uid = data["account_uid"] note._debit_account_uid = data["debit_account_uid"] note._uid = data["uid"] note._debit_note_uid = data["debit_note_uid"] note._datetime = _string_to_datetime(data["datetime"]) note._value = _create_decimal(data["value"]) note._is_provisional = data["is_provisional"] if note._is_provisional: note._receipt_by = _string_to_datetime(data["receipt_by"]) return note
def validate_is_uid(uid): """Validate that the passed 'uid' is actually a UID. This checks that the string is not something weird that is trying to break the system """ if uid is None: raise TypeError("'None' is not a valid UID!") uid = str(uid) len_uid = len(uid) import re as _re from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime if len_uid == 8: # this is a short UID if _re.match(r'[a-f0-9]{8}', uid): return elif len_uid == 35: # this is a short UID with a datetime parts = uid.split("/") try: dt = _string_to_datetime(parts[0]) if _re.match(r'[a-f0-9]{8}', parts[1]): return except Exception as e: print(e) pass elif len_uid == 36: # this is a long UID if _re.match( r'[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}', uid): return elif len_uid == 63: # this is a long UID with a datetime parts = uid.split("/") try: dt = _string_to_datetime(parts[0]) if _re.match( r'[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}', parts[1]): return except: pass raise TypeError("'%s' is not a valid UID!" % uid)
def from_data(data): """Return an authorisation created from the json-decoded dictionary""" auth = Authorisation() if (data and len(data) > 0): from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime from Acquire.ObjectStore import string_to_bytes \ as _string_to_bytes auth._user_uid = data["user_uid"] auth._session_uid = data["session_uid"] auth._identity_url = data["identity_url"] auth._identity_uid = data["identity_uid"] auth._uid = data["uid"] parts = auth._uid.split("/") auth._auth_datetime = _string_to_datetime(parts[0]) auth._signature = _string_to_bytes(data["signature"]) auth._siguid = _string_to_bytes(data["siguid"]) auth._last_validated_datetime = None if "is_testing" in data: auth._is_testing = data["is_testing"] return auth
def _get_driver_details_from_data(data): from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime import copy as _copy details = _copy.copy(data) if "created_datetime" in details: details["created_datetime"] = _string_to_datetime( details["created_datetime"]) return details
def from_data(data, passphrase=None): """Return a OSPar constructed from the passed json-deserliased dictionary Args: data (dict): JSON-deserialised dictionary from which to create OSPar Returns: OSPar: OSPar object created from dict """ if data is None or len(data) == 0: return OSPar() from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime from Acquire.ObjectStore import string_to_bytes \ as _string_to_bytes par = OSPar() par._url = _string_to_bytes(data["url"]) par._key = data["key"] par._uid = data["uid"] if par._key is not None: par._key = str(par._key) par._expires_datetime = _string_to_datetime(data["expires_datetime"]) par._is_readable = data["is_readable"] par._is_writeable = data["is_writeable"] if "service_url" in data: par._service_url = data["service_url"] if "privkey" in data: if passphrase is not None: from Acquire.Crypto import PrivateKey as _PrivateKey par._privkey = _PrivateKey.from_data(data["privkey"], passphrase) # note that we don't load the driver details as this # is stored and loaded separately on the service return par
def _get_driver_details_from_data(data): """Internal function used to get the OCI driver details from the passed data Args: data (dict): Dict holding OCI driver details Returns: dict: Dict holding OCI driver details """ from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime import copy as _copy details = _copy.copy(data) if "created_datetime" in details: details["created_datetime"] = _string_to_datetime( details["created_datetime"]) return details
def from_data(data): """Return a PAR constructed from the json-deserialised passed dictionary """ if data is None or len(data) == 0: return PAR() f = PAR() from Acquire.Client import Location as _Location from Acquire.Client import ACLRule as _ACLRule from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime f._location = _Location.from_data(data["location"]) f._aclrule = _ACLRule.from_data(data["aclrule"]) f._expires_datetime = _string_to_datetime(data["expires_datetime"]) f._uid = data["uid"] return f
def from_data(data): """Return a new FileMeta constructed from the passed json-deserialised dictionary """ f = FileMeta() if data is not None and len(data) > 0: f._filename = data["filename"] if "uid" in data: f._uid = data["uid"] if "filesize" in data: f._filesize = data["filesize"] if "checksum" in data: f._checksum = data["checksum"] if "user_guid" in data: f._user_guid = data["user_guid"] if "datetime" in data: from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime f._datetime = _string_to_datetime(data["datetime"]) if "compression" in data: f._compression = data["compression"] if "acl" in data: from Acquire.Client import ACLRule as _ACLRule f._acl = _ACLRule.from_data(data["acl"]) if "aclrules" in data: from Acquire.Storage import ACLRules as _ACLRules f._aclrules = _ACLRules.from_data(data["aclrules"]) return f
def read(self, spend, resource, receipt_by): """Read the cheque - this will read the cheque to return the decrypted contents. This will only work if this function is called on the accounting service that will cash the cheque, if the signature on the cheque matches the service that is authorised to cash the cheque, and if the passed resource matches the resource encoded in the cheque. If this is all correct, then the returned dictionary will contain; {"recipient_url": The URL of the service which was sent the cheque, "recipient_key_fingerprint": Verified fingerprint of the service key that signed this cheque "spend": The amount authorised by this cheque, "uid": The unique ID for this cheque, "resource": String that identifies the resource this cheque will be used to pay for, "account_uid": UID of the account from which funds will be drawn "authorisation" : Verified authorisation from the user who says they own the account for the spend "receipt_by" : Time when we must receipt the cheque, or we will lose the money } You must pass in the spend you want to draw from the cheque, a string representing the resource this cheque will be used to pay for, and the time by which you promise to receipt the cheque after cashing Args: spend (Decimal): Amount authorised by cheque resource (str): Resource to pay for receipt_by (datetime): Time cheque must be receipted by Returns: dict: Dictionary described above """ if self._cheque is None: raise PaymentError("You cannot read a null cheque") from Acquire.ObjectStore import string_to_decimal \ as _string_to_decimal from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime from Acquire.ObjectStore import datetime_to_string \ as _datetime_to_string from Acquire.Service import get_this_service as _get_this_service spend = _string_to_decimal(spend) resource = str(resource) receipt_by = _string_to_datetime(receipt_by) service = _get_this_service(need_private_access=True) # get the cheque data - this may have been signed try: cheque_data = _json.loads(self._cheque["signed_data"]) except: cheque_data = self._cheque # decrypt the cheque's data - only possible on the accounting service cheque_data = service.decrypt_data(cheque_data) # the date comprises the user-authorisation that acts as a # signature that the user wrote this cheque, and the info # for the cheque to say how it is valid from Acquire.Identity import Authorisation as _Authorisation auth = _Authorisation.from_data(cheque_data["authorisation"]) info = cheque_data["info"] # the json.dumps version is the resource used to verify # the above authorisation auth_resource = info # validate that the user authorised this cheque try: auth.verify(resource=info) except Exception as e: raise PaymentError( "The user's signature/authorisation for this cheque " "is not valid! ERROR: %s" % str(e)) info = _json.loads(info) # the user signed this cheque :-) info["authorisation"] = auth # check the signature if one was needed try: recipient_url = info["recipient_url"] except: recipient_url = None if recipient_url: # the recipient was specified - verify that we trust # the recipient, and that they have signed the cheque recipient_service = service.get_trusted_service( service_url=recipient_url) recipient_service.verify_data(self._cheque) info["recipient_key_fingerprint"] = self._cheque["fingerprint"] # validate that the item signature is correct try: cheque_resource = info["resource"] except: cheque_resource = None if cheque_resource is not None: if resource != resource: raise PaymentError( "Disagreement over the resource for which " "this cheque has been signed") info["resource"] = resource info["auth_resource"] = auth_resource try: max_spend = info["max_spend"] del info["max_spend"] except: max_spend = None if max_spend is not None: max_spend = _string_to_decimal(max_spend) if max_spend < spend: raise PaymentError( "The requested spend (%s) exceeds the authorised " "maximum value of the cheque" % (spend)) info["spend"] = spend try: expiry_date = info["expiry_date"] del expiry_date["expiry_date"] except: expiry_date = None if expiry_date is not None: expiry_date = _string_to_datetime(expiry_date) # validate that the cheque will not have expired # when we receipt it from Acquire.ObjectStore import get_datetime_now \ as _get_datetime_now now = _get_datetime_now() if now > receipt_by: raise PaymentError( "The time when you promised to receipt the cheque " "has already passed!") if receipt_by > expiry_date: raise PaymentError( "The cheque will have expired after you plan to " "receipt it!: %s versus %s" % (_datetime_to_string(receipt_by), _datetime_to_string(expiry_date))) info["receipt_by"] = receipt_by return info
def _get_user_public_cert(self, scope=None, permissions=None): """Internal function that returns the public certificate of the user who signed this authorisation. This will check that the authorisation was not signed after the user logged out, as well as validating the services that provide the user session keys etc. """ must_fetch = False try: if scope != self._scope or permissions != self._permissions: must_fetch = True except: must_fetch = True if self._pubcert is not None: if not must_fetch: try: return self._pubcert except: pass try: testing_key = self._testing_key except: testing_key = None if testing_key is not None: if not self._is_testing: raise PermissionError( "You cannot pass a test key to a non-testing " "Authorisation") return testing_key # we need to get the public signing key for this session from Acquire.Service import get_trusted_service \ as _get_trusted_service from Acquire.ObjectStore import get_datetime_now \ as _get_datetime_now try: identity_service = _get_trusted_service(self._identity_url) except: raise PermissionError( "Unable to verify the authorisation as we do not trust " "the identity service at %s" % self._identity_url) if not identity_service.can_identify_users(): raise PermissionError( "Cannot verify an Authorisation that does not use a " "valid identity service") if identity_service.uid() != self._identity_uid: raise PermissionError( "Cannot auth_once this Authorisation as the actual UID of " "the identity service at '%s' (%s) does not match " "the UID of the service that signed this authorisation " "(%s)" % (self._identity_url, identity_service.uid(), self._identity_uid)) response = identity_service.get_session_info( session_uid=self._session_uid, scope=scope, permissions=permissions) try: user_uid = response["user_uid"] except: pass if self._user_uid != user_uid: raise PermissionError( "Cannot verify the authorisation as there is " "disagreement over the UID of the user who signed " "the authorisation. %s versus %s" % (self._user_uid, user_uid)) try: logout_datetime = _string_to_datetime(response["logout_datetime"]) except: logout_datetime = None if logout_datetime: # the user has logged out from this session - ensure that # the authorisation was created before the user logged out if logout_datetime < self.signature_time(): raise PermissionError( "This authorisation was signed after the user logged " "out. This means that the authorisation is not valid. " "Please log in again and create a new authorisation.") from Acquire.Crypto import PublicKey as _PublicKey pubcert = _PublicKey.from_data(response["public_cert"]) self._pubcert = pubcert self._scope = scope self._permissions = permissions return pubcert
def from_key(key): """Extract information from the passed object store key. This looks for a string that is; isoformat_datetime/UID/transactioncode where transactioncode is a string that matches '2 letters followed by a number' CL000100.005000 DR000004.234100 etc. For sent and received receipts there are two values; the receipted value and the original estimate. These have the standard format if the values are the same, e.g. RR000100.005000 however, they have original value T receipted value if they are different, e.g. RR000100.005000T000090.000000 Args: key: Object store key """ from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime from Acquire.Accounting import create_decimal as _create_decimal parts = key.split("/") # start at the end... nparts = len(parts) for i in range(0, nparts): j = nparts - i - 1 t = TransactionInfo() try: t._datetime = _string_to_datetime(parts[j - 2]) except: continue t._uid = parts[j - 1] part = parts[j] try: code = TransactionInfo._get_code(part[0:2]) if code == TransactionCode.SENT_RECEIPT or \ code == TransactionCode.RECEIVED_RECEIPT: values = part[2:].split("T") try: value = _create_decimal(values[0]) receipted_value = _create_decimal(values[1]) t._code = code t._value = value t._receipted_value = receipted_value return t except: pass value = _create_decimal(part[2:]) t._code = code t._value = value t._receipted_value = None return t except: pass raise ValueError("Cannot extract transaction info from '%s'" % (key))
def from_data(data): """Return a LoginSession constructed from the passed data (dictionary) """ l = LoginSession() if data is not None and len(data) > 0: from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime from Acquire.Crypto import PublicKey as _PublicKey l._uid = data["uid"] l._username = data["username"] l._request_datetime = _string_to_datetime(data["request_datetime"]) l._pubcert = _PublicKey.from_data(data["public_certificate"]) l._status = data["status"] try: l._pubkey = _PublicKey.from_data(data["public_key"]) except: l._pubkey = None try: l._login_datatime = _string_to_datetime(data["login_datetime"]) except: pass try: l._logout_datetime = _string_to_datetime( data["logout_datetime"]) except: pass try: l._ipaddr = data["ipaddr"] except: pass try: l._hostname = data["hostname"] except: pass try: l._login_message = data["login_message"] except: pass try: l._scope = data["scope"] except: pass try: l._permissions = data["permissions"] except: pass try: l._user_uid = data["user_uid"] except: pass try: l._device_uid = data["device_uid"] except: pass return l
def lock(self, timeout=None, lease_time=None): """Lock the mutex, blocking until the mutex is held, or until 'timeout' seconds have passed. If we time out, then an exception is raised. The lock is held for a maximum of 'lease_time' seconds. Args: timeout (int): Number of seconds to block lease_time (int): Number of seconds to hold the lock Returns: None """ # if the user does not provide a timeout, then we will set a timeout # to 10 seconds if timeout is None: timeout = 10.0 else: timeout = float(timeout) # if the user does not provide a lease_time, then we will set a # default of only 10 seconds if lease_time is None: lease_time = 10.0 else: lease_time = float(lease_time) from Acquire.ObjectStore import get_datetime_now as _get_datetime_now from Acquire.ObjectStore import datetime_to_string \ as _datetime_to_string from Acquire.ObjectStore import string_to_datetime \ as _string_to_datetime from Acquire.ObjectStore import ObjectStore as _ObjectStore if self.is_locked(): # renew the lease - if there is less than a second remaining # on the lease then unlock and then lock again from scratch now = _get_datetime_now() if (now > self._end_lease) or (now - self._end_lease).seconds < 1: self.fully_unlock() self.lock(timeout, lease_time) else: self._end_lease = now + _datetime.timedelta(seconds=lease_time) self._lockstring = "%s{}%s" % ( self._secret, _datetime_to_string(self._end_lease)) _ObjectStore.set_string_object(self._bucket, self._key, self._lockstring) self._is_locked += 1 return now = _get_datetime_now() endtime = now + _datetime.timedelta(seconds=timeout) # This is the first time we are trying to get a lock while now < endtime: # does anyone else hold the lock? try: holder = _ObjectStore.get_string_object( self._bucket, self._key) except: holder = None is_held = True if holder is None: is_held = False else: end_lease = _string_to_datetime(holder.split("{}")[-1]) if now > end_lease: # the lease from the other holder has expired :-) is_held = False if not is_held: # no-one holds this mutex - try to hold it now self._end_lease = now + _datetime.timedelta(seconds=lease_time) self._lockstring = "%s{}%s" % ( self._secret, _datetime_to_string(self._end_lease)) _ObjectStore.set_string_object(self._bucket, self._key, self._lockstring) holder = _ObjectStore.get_string_object( self._bucket, self._key) else: self._lockstring = None if holder == self._lockstring: # it looks like we are the holder - read and write again # just to make sure holder = _ObjectStore.get_string_object( self._bucket, self._key) if holder == self._lockstring: # write again just to make sure _ObjectStore.set_string_object(self._bucket, self._key, self._lockstring) holder = _ObjectStore.get_string_object( self._bucket, self._key) if holder == self._lockstring: # we have read and written our secret to the object store # three times. While a race condition is still possible, # I'd hope it is now highly unlikely - we now hold the mutex self._is_locked = 1 return # only try the lock 4 times a second _time.sleep(0.25) now = _get_datetime_now() from Acquire.ObjectStore import MutexTimeoutError raise MutexTimeoutError("Cannot acquire a mutex lock on the " "key '%s'" % self._key)