def revoke_arrangement(id_as_hex): """ REST endpoint for revoking/deleting a KFrag from a node. """ from nucypher.policy.collections import Revocation revocation = Revocation.from_bytes(request.data) log.info("Received revocation: {} -- for arrangement {}".format( bytes(revocation).hex(), id_as_hex)) # Check that the request is the same for the provided revocation if not id_as_hex == revocation.arrangement_id.hex(): log.debug("Couldn't identify an arrangement with id {}".format( id_as_hex)) return Response(status_code=400) try: with datastore.describe(PolicyArrangement, id_as_hex, writeable=True) as policy_arrangement: if revocation.verify_signature( policy_arrangement.alice_verifying_key): policy_arrangement.delete() except (DatastoreTransactionError, InvalidSignature) as e: log.debug("Exception attempting to revoke: {}".format(e)) return Response( response='KFrag not found or revocation signature is invalid.', status=404) else: log.info("KFrag successfully removed.") return Response(response='KFrag deleted!', status=200)
def reencrypt_via_rest(id_as_hex): # Get Policy Arrangement try: arrangement_id = binascii.unhexlify(id_as_hex) except (binascii.Error, TypeError): return Response(response=b'Invalid arrangement ID', status=405) try: # Get KFrag # TODO: Yeah, well, what if this arrangement hasn't been enacted? 1702 with datastore.describe(PolicyArrangement, id_as_hex) as policy_arrangement: kfrag = policy_arrangement.kfrag alice_verifying_key = policy_arrangement.alice_verifying_key except RecordNotFound: return Response(response=arrangement_id, status=404) # Get Work Order from nucypher.policy.collections import WorkOrder # Avoid circular import alice_address = canonical_address_from_umbral_key(alice_verifying_key) work_order_payload = request.data work_order = WorkOrder.from_rest_payload( arrangement_id=arrangement_id, rest_payload=work_order_payload, ursula=this_node, alice_address=alice_address) log.info( f"Work Order from {work_order.bob}, signed {work_order.receipt_signature}" ) # Re-encrypt response = this_node._reencrypt( kfrag=kfrag, work_order=work_order, alice_verifying_key=alice_verifying_key) # Now, Ursula saves this workorder to her database... # Note: we give the work order a random ID to store it under. with datastore.describe(Workorder, str(uuid.uuid4()), writeable=True) as new_workorder: new_workorder.arrangement_id = work_order.arrangement_id new_workorder.bob_verifying_key = work_order.bob.stamp.as_umbral_pubkey( ) new_workorder.bob_signature = work_order.receipt_signature headers = {'Content-Type': 'application/octet-stream'} return Response(headers=headers, response=response)
def set_policy(id_as_hex): """ REST endpoint for setting a kFrag. """ policy_message_kit = UmbralMessageKit.from_bytes(request.data) alices_verifying_key = policy_message_kit.sender_verifying_key alice = _alice_class.from_public_keys( verifying_key=alices_verifying_key) try: cleartext = this_node.verify_from(alice, policy_message_kit, decrypt=True) except InvalidSignature: # TODO: Perhaps we log this? Essentially 355. return Response(status_code=400) if not this_node.federated_only: # This splitter probably belongs somewhere canonical. transaction_splitter = BytestringSplitter(32) tx, kfrag_bytes = transaction_splitter(cleartext, return_remainder=True) try: # Get all of the arrangements and verify that we'll be paid. # TODO: We'd love for this part to be impossible to reduce the risk of collusion. #1274 arranged_addresses = this_node.policy_agent.fetch_arrangement_addresses_from_policy_txid( tx, timeout=this_node.synchronous_query_timeout) except TimeExhausted: # Alice didn't pay. Return response with that weird status code. this_node.suspicious_activities_witnessed['freeriders'].append( (alice, f"No transaction matching {tx}.")) return Response(status=402) this_node_has_been_arranged = this_node.checksum_address in arranged_addresses if not this_node_has_been_arranged: this_node.suspicious_activities_witnessed['freeriders'].append( (alice, f"The transaction {tx} does not list me as a Worker - it lists {arranged_addresses}." )) return Response(status=402) else: _tx = NO_BLOCKCHAIN_CONNECTION kfrag_bytes = cleartext kfrag = KFrag.from_bytes(kfrag_bytes) if not kfrag.verify(signing_pubkey=alices_verifying_key): raise InvalidSignature("{} is invalid".format(kfrag)) with datastore.describe(PolicyArrangement, id_as_hex, writeable=True) as policy_arrangement: if not policy_arrangement.alice_verifying_key == alice.stamp.as_umbral_pubkey( ): raise alice.SuspiciousActivity policy_arrangement.kfrag = kfrag # TODO: Sign the arrangement here. #495 return "" # TODO: Return A 200, with whatever policy metadata.
def consider_arrangement(): from nucypher.policy.policies import Arrangement arrangement = Arrangement.from_bytes(request.data) # TODO: Look at the expiration and figure out if we're even staking that long. 1701 with datastore.describe(PolicyArrangement, arrangement.id.hex(), writeable=True) as new_policy_arrangement: new_policy_arrangement.arrangement_id = arrangement.id.hex( ).encode() new_policy_arrangement.expiration = arrangement.expiration new_policy_arrangement.alice_verifying_key = arrangement.alice.stamp.as_umbral_pubkey( ) # TODO: Fine, we'll add the arrangement here, but if we never hear from Alice again to enact it, # we need to prune it at some point. #1700 headers = {'Content-Type': 'application/octet-stream'} # TODO: Make this a legit response #234. return Response( b"This will eventually be an actual acceptance of the arrangement.", headers=headers)