Esempio n. 1
0
	def prepare_user(self):
		'''
		Goal: prepare a user service instance - by creating one.
		Returns user:UserInstance
		Exceptions:
			Raises:
				ValueError:
					"Coudn't prepare a test user." is caught in cases when one tries to create a user, which already exists -> excepted with a discharge of a user and a resubmission.
					"Still cound't preare a test user." - raised when the discharge,resubmission hasn't helped.

		'''
		user=UserService()
		payload={
			'user_data':{
				'password':'******',
				**self.dummy_identification_payload['signup']
			},
			'key_data':{
				'public_key':5,
				'private_key':{'iv':'str','data':'str'}
			}
		}

		try:
			assert user.signup(**payload), ValueError('Couldn\'t prepare a test user.')
		except:
			self.discharge_user()
			assert user.signup(**payload), ValueError('Still couldn\'t prepare a test user.')

		return user
Esempio n. 2
0
    def test_invalid_login_invalid_activity(self):
        '''
		Goal: test a request aimed at the signup, providing identification data for already existing user.
		Verifies, that the verification token would be denied according to the activity state update.
		'''

        preaccess_token = self.preaccess_token('login')

        self.prepare_user()

        user = UserService(username='******')

        verification_token = self.verification_token(
            identification_data=self.dummy_identification_payload['login'],
            preaccess=preaccess_token.value,
            activity=user.activity_state)

        time.sleep(5)

        user.update_activity()

        client = self.app.test_client()

        response = client.post(
            '/api/tokens/grant',
            headers={'Authorization': f'Bearer {verification_token.value}'},
            json=self.dummy_auth_payload['login'])

        self.assertEqual(response.status_code, 401)
Esempio n. 3
0
	def discharge_user(self):
		'''
		Goal: remove/delete a test user instance.
		Returns:None
		Exceptions:
			Raises:
				ValueError - in cases,when one tries to discharge a user instance, which is not related to any user. 
		'''
		user=UserService(username='******')
		assert user.remove(), ValueError('Coudn\'t find a test user to remove.')
Esempio n. 4
0
    def test_valid_login(self):
        '''
		Goal: test a request aimed at the signup, providing valid json,header /w absent user.
		'''
        self.prepare_user()

        preaccess_token = self.preaccess_token('login')

        verification_token = self.verification_token(
            identification_data=self.dummy_identification_payload['login'],
            preaccess=preaccess_token.value,
            activity=(UserService(username='******')).activity_state)

        client = self.app.test_client()

        response = client.post(
            '/api/tokens/grant',
            headers={'Authorization': f'Bearer {verification_token.value}'},
            json=self.dummy_auth_payload['login'])

        self.assertEqual(response.status_code, 201)

        self.assertIn('grant_token', response.json)

        self.discharge_user()
Esempio n. 5
0
		def validate(*args,**kwargs):

			#Exceptions
			assert len(args)>1, Exception('No headers has been found.')
			assert isinstance((headers:=args[1]),dict), TypeError('Headers must be a dictionary.')
			assert (True if (authorization:=kwargs.pop('authorization',{token_type:{}}))=={token_type:{}} else (True if authorization.get(token_type,None) is None else False)), Exception(f'"{token_type}" is already in the authorization chain.')
			

			#Validation

			#Initialize lambda functions for the 1.:
			search = lambda head,raw: match.group() if (match:=re.search(f'(?<={head})([^\s]+)',raw)) else None
			token_raw_data = lambda l,d: search('Bearer ',d) if l=='Authorization' else (search(f'{token_type}_token=',d) if l=='Cookie' else d)
			locate = lambda l,h: {'location':l, 'object':Token(raw_data=token_raw_data(l,raw) ) } if (raw:=h.get(l)) else {'location':l,'object':None}
			
			#Initialize lambda functions for the 3.2:
			find_case = lambda cases: next(iter(tupled)) if (tupled:=tuple(filter(lambda case: case is not None,cases))) else None
			map_cases = lambda **credentials: map(lambda identification: case if (case:=UserService(**{identification:credentials[identification]})).id else None,credentials)
			resolve_user = lambda **identification: find_case(map_cases(**identification))
			
			either = auth_field_case if (auth_field_case:=locate('Authorization',headers)).get('object') else (cookie_field_case if (cookie_field_case:=locate('Cookie',headers)).get('object') else {'location':None,'object':None})
			#Validation:1.
			if (token:=locate(location,headers) if location else either)['object'] and token['object'].is_valid and token['object']['token_type']==token_type:
				#Validation:2.
				#Validation:3 ~> valid_ownership|valid_verification|valid_preaccess.

				valid_preaccess = lambda t : {'valid':True,'status_code':200} if any(True for route in ('signup','login') if t['object']['route']==route) else {'valid':False,'status_code':401}

				valid_verification = lambda t : {'valid':True,'status_code':200} if \
				( None!=t['object']['activity'] ==\
					( (None if (resolve_user(username=(identification:=t['object']['identification_data'])['username'],email=identification['email'])) else 0 )\
					if (preaccess:=Token(raw_data=t['object']['preaccess']))['route']=='signup' else\
					(resolved_user.activity_state if (resolved_user:=resolve_user(username=(identification:=t['object']['identification_data']['identification']),email=identification)) else None) ) \
				)\
				else {'valid':False,'status_code':401}


				valid_ownership = lambda t: {'valid':True,'status_code':200, 'owner':owner} if\
				None != (owner:=UserService(id=t['object']['user_id'])).activity_state == t['object']['activity']\
				else {'valid':False,'status_code':401, 'owner':None}
				
				authorization[token_type] = {'token':token,\
				**(valid_ownership(token) if token_type in ('grant','access','confirmation')\
				else (valid_verification(token) if token_type=='verification'\
				else (valid_preaccess(token) if token_type=='preaccess'\
				else {'valid':True,'status_code':200}) ) )}
Esempio n. 6
0
    def test_invalid_login_absent(self):
        '''
		Goal: test a request aimed at the login, providing data for a user that doesn't exist , has been discharged after the generation of a verification token.
		Verifies, that the verification token would be denied according to the activity state update or better say absense of such.
		'''

        preaccess_token = self.preaccess_token('login')
        self.prepare_user()

        verification_token = self.verification_token(
            identification_data=self.dummy_identification_payload['login'],
            preaccess=preaccess_token.value,
            activity=(UserService(username='******')).activity_state)

        self.discharge_user()

        client = self.app.test_client()

        response = client.post(
            '/api/tokens/grant',
            headers={'Authorization': f'Bearer {verification_token.value}'},
            json=self.dummy_auth_payload['login'])

        self.assertEqual(response.status_code, 401)
Esempio n. 7
0
    def accept(self, headers, data, **kwargs):
        '''
		Goal : Mail verification_token to an email , based on the provided <identification_data> - thus allowing a user to proceed to verify themselves.

		Arguments:headers:dict, data:dict, kwargs:key-word-argument.

			headers : meant to contain all headers data , in this particular case - a cookie field as a sign of authority, must contain a preaccess_token = {route:["signup"/"login"],token_type:"preaccess",dnt}.
			Note:
				This argument is used in the authorized decorator - to perform proper authorization process, the result of which is stored in the kwargs.
				To know more about the authorized decorator - view a separate documentation for the authorized method in the chathouse/utilities/security/validation/headers.py.
			
			data : meant to store any data that's passed into the request - json body. The could be 2 cases:
		  		signup:<identification_data>:{email:str,username:str,name:str,about:str}
		   		or
		  		login:<identification_data>={identification:str}
		  	Note:
		  		This argument is used in the verification process of the incoming request data, which is handled by the derived class template - which on itself is a result of create_a_template function, meant to return a proper template instance according to the route.
		  		To know more about the create_a_template - view a separate documentation for the create_a_template function in the ./template.py.
			
			kwargs: meant to store any data passed into the accept method, from the initial requrest, up to the authorization steps. In particular stores the authorization key , which on it's own stores shall store more nested information related to a token_type.
			In this instance the token_type is the preaccess one - so kwargs shall store:{
				authorization:{
					preaccess:{
						valid:bool,
						status:int,
						token:{
							object:None|Token,
							location:str
						}
					}
				}
			}


	 	Full verification:
	 		0.Verify the preaccess_token;
	 			If invalid respond with 401;
	  			Otherwise resume with the next steps.
  			1.Extract the route value from the token and create a proper template.
  			2.Validate the data against the proper template.
  			3.Resolve the user's email and activity using the resolve function, which returns a : dictionary of {'email':str,'activity':int} | None , based on the route and identification data.
  			If the email has been resolved :
	  			Proceed to send the email and respond accordingly with 201.
	  		Otherwise:
				Respond accordingly with 400.
	   
	   	Lambda functions:
	   		[Note each lambda function shall be called from bottom up.]s

			find_case:

				Goal: return the very first case of existing UserService from the submited search cases.
				Arguments: cases:map of cases:UserService|None.
				Returns: very first UserService instance.
				[Note at this point there must be a UserService instance, with the help of explicit validation with any(). But if there isn't one - error will not arise due to the tuple verification]

	   		map_cases: 

	   			Goal:create a map object of iterated UserService instances for email and username cases. Iteration itself checks if the instance has an id -> returns the UserService if instance has an id else None.
	   			Arguments: data:key word argument.
	   			Returns: map object.

	   		resolve:

	   			Goal: resolve email based on the identification data , by verify if the such data is appropriate according to a certain route.
	   			If the route is signup:
	   				Get respective map_cases, then :
	   					If not even one case (not any function) is valid return:
	   						{'email':as email from the provided data, 'activity': as 0}
	   					Otherwise return None
				Otherwise:
					Get respective map_cases, then convert cases into a tuple:
						If there is a case, which isn't None - then return the very next element of the filtered cases , where every case must not be a None - thus returning:
							{'email':resolved user's email, 'activity':current activity_dnt state of the resolved user}.
						Otherwise return None.
				Returns: {email:str,activir:int}|None.    

		Generation:
	  		verification_token={identification_data:<identification_data>,token_type:"verification", activity:<current_activity_dnt_state>, dnt,preaccess:<preaccess_token>}.

	 	Returns:
	 		If verified: 201,{success:True,email_sent:True}
	  		Otherwise:
	   			Failed to verify the token: 401,{success:False,message:"Unauthorized."}
	   			Failed to validate the json body: 400,{success:False,message:"Incorrect json data."}
		'''
        #Code
        #Exceptions
        assert all(
            map(lambda argument: isinstance(argument, dict), (headers, data))
        ), TypeError(
            'Arguments , such as : headers and data - must be dictionaries')

        #Lambda functions

        find_case = lambda cases: next(iter(tupled)) if (tupled := (tuple(
            filter(lambda case: case is not None, cases)))) else None

        map_cases = lambda **credentials: map(
            lambda identification: case
            if (case := UserService(**{
                identification: credentials[identification]
            })).id else None, credentials)

        resolve = lambda route,data: ( {'email':data['email'],'activity':0} if not any(map_cases(email=data['email'],username=data['username'])) else None ) if route=='signup' \
       else ({'email':case.email, 'activity': case.activity_state } if any( (cases:=tuple( map_cases(email=data['identification'],username=data['identification']) ) ) ) and (case:=find_case(cases)) else None)

        #Step 0.
        if not kwargs['authorization']['preaccess']['valid']:
            return {
                'success': 'False',
                'message': 'Unauthorized!',
                'reason': 'Invalid preaccess token.'
            }, 401

        #Step 1.
        template = create_a_template(route := kwargs['authorization']
                                     ['preaccess']['token']['object']['route'])

        #Step 2.
        #Step 3.
        if template.validate(**data) and (resolution := resolve(
                route, (data := template.data))) is not None:

            verification_token = Token(
                payload_data={
                    'identification_data':
                    data,
                    'token_type':
                    'verification',
                    'activity':
                    resolution['activity'],
                    'preaccess':
                    kwargs['authorization']['preaccess']['token']
                    ['object'].value,
                    'exp':
                    current_app.config['VERIFICATION_EXP']
                })

            MailService.send(
                recipients=[resolution['email']],
                body=
                f"There has been a request to {route}, using this email. If you wish to proceed with the verification , follow this url http://127.0.0.1:5000/verify/{verification_token.value} .\nOtherwise please ignore this email.",
                subject="Verification email.")

            return {'success': 'True', 'message': 'Email has been sent.'}, 201
Esempio n. 8
0
	def accept(self,headers,data,**kwargs):
		'''
		Goal : establish/create a chat instance and join the chat on the behalf of the requester and the other participant, if provided.

		Arguments:headers:dict, data:dict, kwargs:key-word-argument.

			headers : meant to contain all headers data , in this particular case - an Authorization field as a sign of authority, must contain a "Bearer <token> , which is the access_token:
				access_token={user_id:int, token_type: "access":str, activity:int , dnt:float}
			Note:
				This argument is used in the authorized decorator - to perform proper authorization process, the result of which is stored in the kwargs.
				To know more about the authorized decorator - view a separate documentation for the authorized method in the chathouse/utilities/security/validation/headers.py.
			
			data : meant to store any data that's passed into the request - json body, there could 2 cases:
		  		With another participant:
		  		{
					name:str,
					participnat_id:<int>
		  		}
		   		or without one:
		  		{
		  			name:str
		  		}
		  	Note:
		  		This argument is used in the verification process of the incoming request data, which is handled by the derived class template - which on itself is a result of create_a_template function, meant to return a proper template instance according to the route.
		  		To know more about the create_a_template - view a separate documentation for the create_a_template function in the ./template.py.
		  	
			kwargs: meant to store any data passed into the accept method, from the initial requrest, up to the authorization steps. In particular stores the authorization key , which on it's own stores shall store more nested information related to a token_type.
			In this instance the token_type is the access one - so kwargs shall store:{
				authorization:{
					access:{
						valid:bool,
						status:int,
						owner:UserService|None,
						token:{
							object:None|Token,
							location:str|None
						}
					}
				}
			}
		
		Lambda functions:
			resolve:
				Goal: resolve a UserService instance with existing inner user instance, based on the provided provided identification.
				Arguments:credentials:key-word-argument. Expecting a key/value pair such as id/<int>.
				Actions:
					If there is a UserService instance with inner existing user instance:
						Such participant exists - return ther UserService instance
					Otherwise return None
				Returns: UserService instance | None

	 	Full verification and actions:
	  		0.Verify the access_token , which on it's own - verifies ownership - makes sure of the existance of a user with the user_id - establishing a UserService, and verifies the provided activity with the current one related to the UserService :
  				If 0. is invalid - disconnect the client.
  				[Note, on the response the user reconnects ,after they try to reestablish a new access_token]
	  			Otherwise proceed to the next steps.
	  		1.At this point the access_token is valid - validate the incoming data:
	  			Set up a template - using a custom create_template, which builds and returns a Template instance.
	  			Validate the data against the template:
	  				If the verification has been successful and:
	  					If the product of the validation / validated doesn't contain a participant_id set other_participant as None and resume the condition to end up successful. -> step 2.
	  					Otherwise If the product of the validation / validated contains a participant_id and the resolution has returned a UserService - thus has found such user - follow the next step -> step 2.
	  		2.			Owner starts a chat -> creates an instance of a ChatService , If everything has gone well:
		  	2.1				On the behalf of each "soon to be participant" - join the chat.
		  					If at any point a UserService wasn't able to join the chat:
		  						The provided payload - was invalid : the request contained the credentials of users that already were related to the chat. 
		  	2.1[-]				Discharge/Remove the created chat, and mention this to requester/owner.
		  	2.2				Otherwise proceed to the notify each participant of the chat - using the participations property.
	  		2.[-]		Otherwise:
	  							The chat couldn't be created - notify the owner of the request/access_token about the failure
	  		1.[-]		Otherwise - the resolution wasn't able to figure out the user based on the credentials proceed to the mention about the failure.
	  		1.[-]	Otherwise proceed to mention about the failure.


  		Exceptions:
  			Raises:
  				TypeError - if headers and data arguments are not dictionaries.
		'''
	#Code:
		#Exceptions:
		assert all(map(lambda argument: isinstance(argument,dict),(headers,data))), TypeError('Arguments , such as : headers and data - must be dictionaries')

		resolve = lambda **credentials:  instance if (instance:=UserService(**credentials)).id else None

		#Step 0.
		if not kwargs['authorization']['access']['valid'] or (owner:=kwargs['authorization']['access']['owner']) is None:
			disconnect()
			return None
Esempio n. 9
0
    def accept(self, headers, data, **kwargs):
        '''
		Goal : Generate a grant token, based on the <identification_data> from the verification_token and the <authentication_data> from the data of the request.

		Arguments:headers:dict, data:dict, kwargs:key-word-argument.

			headers : meant to contain all headers data , in this particular case - an Authorization field as a sign of authority, must contain a Bearer token , which is the verification_token:
				{identification_data:<identification_data>,token_type:"verification",activity:int,dnt:float,preaccess:<preaccess_token>}.
			Note:
				This argument is used in the authorized decorator - to perform proper authorization process, the result of which is stored in the kwargs.
				To know more about the authorized decorator - view a separate documentation for the authorized method in the chathouse/utilities/security/validation/headers.py.
			
			data : meant to store any data that's passed into the request - json body. The could be 2 cases:
		  		signup:
		  			<authentication_data>:{
				  		password:str,
				  		keyring:{
				  			public_key:str,
							private_key:{
								iv:str,
								data:str
							},
							g:int,
							m:int
							}
						}
		   		or
		  		login:
		  			<authentication_data>:{
				  		password:str
				  	}
		  	Note:
		  		This argument is used in the verification process of the incoming request data, which is handled by the derived class template - which on itself is a result of create_a_template function, meant to return a proper template instance according to the route.
		  		To know more about the create_a_template - view a separate documentation for the create_a_template function in the ./template.py.
			
			kwargs: meant to store any data passed into the accept method, from the initial requrest, up to the authorization steps. In particular stores the authorization key , which on it's own stores shall store more nested information related to a token_type.
			In this instance the token_type is the preaccess one - so kwargs shall store:{
				authorization:{
					verification:{
						valid:bool,
						status:int,
						token:{
							object:None|Token,
							location:str
						}
					}
				}
			}


	 	Full verification:
	  		0.Verify the verification_token:
  			1.Extract the preaccess token from the verification_token and verify it and check existance of the route value.
  				If 0./1. is invalid respond with 401, message:"Invalid verification/preaccess token.";
	  			Otherwise resume with the next steps.
  			2.Having validated the preaccess , extract the route value and create a proper template.
  			3.Verify that the data is a dictionary an proceed to validate the data against the proper template.
  			4.Resolve the appropriate user_service object (/w existing or non existing inner instance of the user) , using the resolve function , which returns a UserService|None, based on the route and <identification_data> 
  			
  			4.If the user_service has been resolved:
  				Then according to the route:
  			5.
  				If route is signup:
  			5.S.1.
  					If either provided Diffie Hellman parameters or public key is invalid:
						Respond with a 409, 'Invalid Diffie Hellman data.'
					Otherwise proceed to the next step:
			5.S.2.
  					Establish a payload using the proper_payload function and If user_service.signup(payload) has been successful:
  						Generate a grant_token and the response shall contain it with a 201.
  					Otherwise:
  						Respond with 409, 'Provided data is invalid.' if the prodived public_key doesn't already exists otherwise 'Please submit again.'
  			5.L.1.
  				Otherwise if the route is login and user_service.login( established payload) has been successful:
  					Generate a grant_token, retrieve a private key from the keyring and DH parameters => inject them into the response, and respond with a 200.
  					At this point the activity_dnt has been upgraded to avoid the usage of previously generated valid tokens.
  				Otherwise:
  					Respond with 401, message:"Invalid authentication data".
  			Otherwise:
  				Respond accordingly with 400, 'Invalid payload data'
	   
	   	Lambda functions:
	   		map_cases: 
	   			Goal:create a map object of iterated UserService instances for email and username cases. Iteration itself checks if the isntance has an id -> returns the UserService case if instance has an id else None.
	   			Arguments: data:key word argument.
	   			Returns: map object.

	   		resolve:
	   			Goal: resolve email based on the identification data , by verify if the such data is appropriate according to a certain route.
	   			If the route is signup:
	   				Get respective map_cases, then :
	   					If not even one case (not any function) is valid return then return a UserService instance with empty inner instance of the user.
	   					Otherwise return None
				Otherwise:
					Get respective map_cases, then convert cases into a tuple:
						If any case isn't None - then return next element of the filtered cases , where every case must not be a None - thus returning an email.
						Otherwise return None.
				Returns: str|None , str - represents an email value.

			valid_dh_parameters:
				Goal: verify if the provided dh parameters are the same as the configured ones, and the provided public is in bounds 0<public_key<modulus.
				Helps to omit requests, which contain invalid DH parameters meant for the key establishments.
				Arguments:initial_keyring:dict - the keyring from the provided data.
				Returns: True|False
				Note: When called the g,m values are popped - so, the keyring now has a following structure:
				keyring:{
					public_key:str,
					private_key:{
						iv:str,
						data:str
						}
					}

			proper_payload:
				Goal: construct a proper payload based on the incoming_route value and incoming_data.
				Arguments: incoming_route:str,incoming_data:dict.
				Actions:
					If the route is signup ( Note: at this point incoming_data consists of : password:str , keyring:{ public_key:str , private_key: { iv:str,data:str } } ):
						return {
							key_data : pop the keyring from the incoming_data
							user_data : {unpack the <identification_data> from the verification token , and unpack the incoming_data}
						}.
					Otherwise the route is login ( Note at this point incoming_data consists of : password:str ):
						return incoming_data.
				Returns: a dictionary.

			token_payload:
				Goal: construct a proper payload_data for the Token, based on the provided service instance.
				Arguments: service:UserService instance.
				Returns: an empty dictionary if the service instance has no inner instance/state, otherwise poceed to create a dictionary of:
				user_id:int(user's id), token_type:str('grant'), activity:int(activity_state of the UserService), exp:dict(configured expiration value for the grant_token - 30 minutes)

		Generation:
  			grant_token={user_id: value:int, token_type: "grant":str, activity: timestamp of UserService(id=value of user_id).activity_dnt , dnt:float}
 
		Returns:
			If either verification token or preaccess token(from the verification token) is invalid or the preaccess token has no route value.
  				Return 401, message:"Invalid verification/preaccess token."
  			Otherwise:
  				If route is signup:
  					If either provided Diffie Hellman parameters or public key is invalid:
						Respond with a 409, 'Invalid Diffie Hellman data.'
					Otherwise:
						 If the user_service.signup(appropriate payload) has been successful:
						 	Return 200, {grant_token:<grant_token>}
						 Otherwise:
						 	Return 409, 'Provided data is invalid.' if the prodived public_key doesn't already exists otherwise 'Please submit again.'
  				Otherwise if the route is login and user_service.login(appropriate payload) has been successful:
  					Return 200, {grant_token:<grant_token>,keyring:{raw:{private_key:<encrypted private_key>}, g:<G>, m:<M>}}
  				Otherwise:
  					Return 401, 'Invalid authentication data.'

  		Exceptions:
  			Raises:
  				TypeError - if headers and data arguments are not dictionaries.
  				ValueError - if the current app  doesn't contain domain Diffie Hellman parameters.
		'''
        #Code:
        #Exceptions:
        assert all(
            map(lambda argument: isinstance(argument, dict), (headers, data))
        ), TypeError(
            'Arguments , such as : headers and data - must be dictionaries')
        assert all(
            map(lambda parameter: isinstance(parameter, int),
                current_app.config.get('DH_PARAMETERS', (None, )))
        ), ValueError(
            'Configuration of the current app must contain domain Diffie Hellman parameters.'
        )

        #Lambda functions:
        find_case = lambda cases: next(iter(tupled)) if (tupled := tuple(
            filter(lambda case: case is not None, cases))) else None

        map_cases = lambda **credentials: map(
            lambda identification: case
            if (case := UserService(**{
                identification: credentials[identification]
            })).id else None, credentials)

        resolve = lambda route,data: (UserService() if not any(map_cases(email=data.get('email',''),username=data.get('username',''))) else None ) if route=='signup'\
        else (case if any( (cases:=tuple( map_cases(email=data.get('identification',''),username=data.get('identification','') ) ) ) ) and (case:=find_case(cases)) else None)

        valid_dh_parameters = lambda initial_keyring: current_app.config[
            'DH_PARAMETERS'] == (
                initial_keyring.pop('g', None),
                initial_keyring.pop('m', None)) and 0 < initial_keyring.get(
                    'public_key', -1) < current_app.config['DH_PARAMETERS'][1]

        proper_payload = lambda incoming_data,incoming_route: { \
          'key_data':incoming_data.pop('keyring', {'public_key':None,'private_key':None}),\
          'user_data':{\
           **kwargs['authorization']['verification']['token']['object']['identification_data'],\
           **incoming_data\
          }\
          } if incoming_route=='signup' else incoming_data


        token_payload = lambda service: {'user_id':service.id,\
        'token_type':'grant',\
        'activity':service.activity_state,\
        'exp':current_app.config['GRANT_EXP']}\
        if getattr(service,'id',None) is not None else {}

        #Step 0.
        #Step 1.
        if not kwargs['authorization']['verification']['valid'] or not (
                preaccess_token :=
                Token(raw_data=kwargs['authorization']['verification']['token']
                      ['object']['preaccess'])
        ).is_valid or not preaccess_token['route']:
            return {
                'success': 'False',
                'message': 'Unauthorized!',
                'reason': 'Invalid verification/preaccess token.'
            }, 401