def set_password(self, message: PyledgerRequest) -> Tuple[bool, bytes]: password = message.data.decode('utf-8') user = User.from_name(message.user) user.set_password(password) DB.session.commit() return True, message.user.encode('utf-8')
def test_1_user(): """ Create a normal user """ create_user('user', 'password') user = User.from_name('user') assert user.get_permissions() == Permissions.USER assert user.check_password('password') == True
def create_user(name, password): kpdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=SECRET, iterations=1000000, backend=password_backend) user = User() user.name = name user.when = datetime.datetime.now() user.set_permissions(Permissions.USER) user.set_password(kpdf.derive(password.encode('utf-8'))) DB.session.add(user) DB.session.commit()
def test_0_master_user(): """ Create a master user """ create_master('password') user = User.from_name('master') assert user.get_permissions() == Permissions.ROOT assert user.check_password('password') == True # Create dummy session session = Session() session.user = user session.key = 'test_session' session.registered = datetime.datetime.now() session.until = datetime.datetime.now() + datetime.timedelta(hours=LIFETIME) DB.session.add(session) DB.session.commit()
def test_2_create_user(): """ Create a user from the API """ request = PyledgerRequest() request.request = 'new_user' request.user = '******' request.password = '******' request.session_key = 'test_session' request.data = pickle.dumps(('user2', 'new_password')) response = PyledgerResponse() response.ParseFromString(handle_request(request.SerializeToString())) assert response.successful == True assert response.data == b'user2' user = User.from_name('user2') assert user.get_permissions() == Permissions.USER assert user.check_password('new_password')
def session(self, message: PyledgerRequest) -> Tuple[bool, bytes]: """ Get authentication key :param message: :return: """ user = User.from_name(message.user) session = Session() session.user = user session.key = str(uuid4()) session.registered = datetime.datetime.now() session.until = datetime.datetime.now() + datetime.timedelta( hours=LIFETIME) DB.session.add(session) DB.session.commit() return True, session.key.encode('utf-8')
def handle_request(payload: bytes): """ Handle a single request :param payload: Serialized PyledgerRequest message :return: """ handler = Handler() message = PyledgerRequest() response = PyledgerResponse() try: message.ParseFromString(payload) except DecodeError: response.successful = False response.data = b'Message not properly formatted' return response.SerializeToString() if message.request not in handler_methods(handler): response.successful = False response.data = 'Request type {} not available'.format( message.request).encode() return response.SerializeToString() else: # Handle authentication if message.request in permissions_registry: user = User.from_name(message.user) permission_required = permissions_registry[message.request] if not user.check_password(message.password): response.successful = False response.data = b'Wrong user and/or password' return response.SerializeToString() if user.get_permissions().value > permission_required.value: response.successful = False response.data = b'Not enough permissions' return response.SerializeToString() session = Session.from_key(message.session_key) if not session: response.successful = False response.data = b'Session not available' return response.SerializeToString() if not session.user == user: response.successful = False response.data = b'Session not owned by this user' return response.SerializeToString() if session.until < datetime.datetime.now(): response.successful = False response.data = b'Session expired, restart your client' return response.SerializeToString() # Select the function from the handler try: print('Handling message', message) successful, result = getattr(handler, message.request)(message) except Exception as exc: successful = False result = b'Exception in user function: ' + repr(exc).encode( 'utf-8') response.successful = successful response.data = result return response.SerializeToString()
def call(self, message: PyledgerRequest) -> Tuple[bool, bytes]: """ Call handler for contract methods. :param message: :return: """ if message.contract not in contract_registry: return False, 'Contract {} not available'.format( message.contract).encode('utf-8') contract = contract_registry[message.contract] if message.call not in methods(contract): return False, 'Method {} not found in contact'.format( message.call).encode('utf-8') if message.call in method_permissions_registry: user = User.from_name(message.user) permission_required = method_permissions_registry[message.call] if not user: if permission_required.value < Permissions.ANON.value: return False, b'Not enough permissions' elif not user.check_password(message.password): return False, b'Wrong user and/or password' elif user.get_permissions().value > permission_required.value: return False, b'Not enough permissions' # Get the last status of the contract. db_contract = Contract.from_name(message.contract) status_data = db_contract.last_status() status = contract._status_class() status.load(status_data.attributes) method = contract.__class__.__dict__[message.call] method_args = pickle.loads(message.data) # Coerce types given the API, since the arguments are pickled method_api = api(contract_registry[message.contract]) signature = method_api[message.call] for arg in method_args: try: method_args[arg] = signature[arg](method_args[arg]) except KeyError: return False, str( ValueError('{} is not a valid key'.format(arg))).encode() # Load additional attributes status.user = message.user status.session = message.session_key # Call the method result = method(status, **method_args) # Persist the new status new_status = Status() new_status.contract = db_contract new_status.attributes = status.dump() new_status.when = datetime.datetime.now() # This is the status chain standard m = hashlib.sha256() m.update(status_data.key) m.update(new_status.when.isoformat().encode('utf-8')) m.update(new_status.attributes) new_status.key = m.digest() DB.session.add(new_status) DB.session.commit() return True, pickle.dumps(result)