Пример #1
0
def unregister(conn: ServerConnection, pwhash: str, wid: str) -> RetVal:
	'''Deletes the online account at the specified server.'''

	if wid and not utils.validate_uuid(wid):
		return RetVal(BadParameterValue, 'bad workspace id')
	
	request = {
		'Action' : 'UNREGISTER',
		'Data' : {
			'Password-Hash' : pwhash
		}
	}
	if wid:
		request['Data']['Workspace-ID'] = wid
	
	status = conn.send_message(request)
	if status.error():
		return status
	
	response = conn.read_response(server_response)

	if response['Code'] == 202:
		return RetVal()

	# This particular command is very simple: make a request, because the server will return
	# one of three possible types of responses: success, pending (for private/moderated 
	# registration modes), or an error. In all of those cases there isn't anything else to do.
	return wrap_server_error(response)
Пример #2
0
def regcode(conn: ServerConnection, regid: str, code: str, pwhash: str, devid: str, 
	devpair: EncryptionPair, domain: str) -> RetVal:
	'''Finishes registration of a workspace'''
	
	request = {
		'Action':'REGCODE',
		'Data':{
			'Reg-Code': code,
			'Password-Hash':pwhash,
			'Device-ID':devid,
			'Device-Key':devpair.public.as_string()
		}
	}

	if domain:
		request['Data']['Domain'] = domain

	if utils.validate_uuid(regid):
		request['Data']['Workspace-ID'] = regid
	else:
		request['Data']['User-ID'] = regid
	
	status = conn.send_message(request)
	if status.error():
		return status
	
	response = conn.read_response(server_response)
	if response.error():
		return response
	
	if response['Code'] != 201:
		return wrap_server_error(response)
	
	return RetVal()
Пример #3
0
def login(conn: ServerConnection, wid: str, serverkey: CryptoString) -> RetVal:
	'''Starts the login process by sending the requested workspace ID.'''
	if not utils.validate_uuid(wid):
		return RetVal(BadParameterValue)

	challenge = b85encode(secrets.token_bytes(32))
	ekey = PublicKey(serverkey)
	status = ekey.encrypt(challenge)
	if status.error():
		return status

	conn.send_message({
		'Action' : "LOGIN",
		'Data' : {
			'Workspace-ID' : wid,
			'Login-Type' : 'PLAIN',
			'Challenge' : status['data']
		}
	})

	response = conn.read_response(server_response)
	if response.error():
		return response
	
	if response['Code'] != 100:
		return wrap_server_error(response)
	
	if response['Data']['Response'] != challenge.decode():
		return RetVal(ServerError, 'server failed to decrypt challenge')
	
	return RetVal()
Пример #4
0
def iscurrent(conn: ServerConnection, index: int, wid='') -> RetVal:
	'''Finds out if an entry index is current. If wid is empty, the index is checked for the 
	organization.'''
	if wid and not utils.validate_uuid(wid):
		return RetVal(AnsBadRequest).set_value('status', 400)
	
	request = {
		'Action' : 'ISCURRENT',
		'Data' : {
			'Index' : str(index)
		}
	}
	if wid:
		request['Data']['Workspace-ID'] = wid
	conn.send_message(request)

	response = conn.read_response(server_response)
	if response.error():
		return response
	
	if response['Code'] != 200:
		return wrap_server_error(response)
	
	if 'Is-Current' not in response['Data']:
		return RetVal(ServerError, 'server did not return an answer')
	
	return RetVal().set_value('iscurrent', bool(response['Data']['Is-Current'] == 'YES'))
Пример #5
0
def devkey(conn: ServerConnection, devid: str, oldpair: EncryptionPair, newpair: EncryptionPair):
	'''Replaces the specified device's key stored on the server'''
	if not utils.validate_uuid(devid):
		return RetVal(AnsBadRequest, 'Invalid device ID').set_value('status', 400)

	conn.send_message({
		'Action' : "DEVKEY",
		'Data' : { 
			'Device-ID': devid,
			'Old-Key': oldpair.public.as_string(),
			'New-Key': newpair.public.as_string()
		}
	})

	# Receive, decrypt, and return the server challenge
	response = conn.read_response(server_response)
	if response.error():
		return response
	
	if response['Code'] != 100:
		return wrap_server_error(response)

	if 'Challenge' not in response['Data'] or 'New-Challenge' not in response['Data']:
		return RetVal(ServerError, 'server did not return both device challenges')
	
	status = oldpair.decrypt(response['Data']['Challenge'])
	if status.error():
		cancel(conn)
		return RetVal(DecryptionFailure, 'failed to decrypt device challenge for old key')

	request = {
		'Action' : "DEVKEY",
		'Data' : { 
			'Response' : status['data']
		}
	}

	status = newpair.decrypt(response['Data']['New-Challenge'])
	if status.error():
		cancel(conn)
		return RetVal(DecryptionFailure, 'failed to decrypt device challenge for new key')
	request['Data']['New-Response'] = status['data']
	conn.send_message(request)

	response = conn.read_response(None)
	if response.error():
		return response
	
	if response['Code'] == 200:
		return RetVal()
	
	return wrap_server_error(response)
Пример #6
0
def device(conn: ServerConnection, devid: str, devpair: EncryptionPair) -> RetVal:
	'''Completes the login process by submitting device ID and its session string.'''
	if not utils.validate_uuid(devid):
		return RetVal(AnsBadRequest, 'Invalid device ID').set_value('status', 400)

	conn.send_message({
		'Action' : "DEVICE",
		'Data' : { 
			'Device-ID' : devid,
			'Device-Key' : devpair.public.as_string()
		}
	})

	# Receive, decrypt, and return the server challenge
	response = conn.read_response(server_response)
	if response.error():
		return response
	
	if response['Code'] != 100:
		return wrap_server_error(response)

	if 'Challenge' not in response['Data']:
		return RetVal(ServerError, 'server did not return a device challenge')
	
	status = devpair.decrypt(response['Data']['Challenge'])
	if status.error():
		cancel(conn)
		return RetVal(DecryptionFailure, 'failed to decrypt device challenge')

	conn.send_message({
		'Action' : "DEVICE",
		'Data' : { 
			'Device-ID' : devid,
			'Device-Key' : devpair.public.as_string(),
			'Response' : status['data']
		}
	})

	response = conn.read_response(None)
	if response.error():
		return response
	
	if response['Code'] == 200:
		return RetVal()
	
	return wrap_server_error(response)
Пример #7
0
def password(conn: ServerConnection, wid: str, pwhash: str) -> RetVal:
	'''Continues the login process sending a password hash to the server.'''
	if not password or not utils.validate_uuid(wid):
		return RetVal(BadParameterValue)
	
	conn.send_message({
		'Action' : "PASSWORD",
		'Data' : { 'Password-Hash' : pwhash }
	})

	response = conn.read_response(server_response)
	if response.error():
		return response
	
	if response['Code'] != 100:
		return wrap_server_error(response)
	
	return RetVal()
Пример #8
0
def setstatus(conn: ServerConnection, wid: str, status: str):
	'''Sets the activity status of the workspace specified. Requires admin privileges'''
	if status not in ['active', 'disabled', 'approved']:
		return RetVal(BadParameterValue, "status must be 'active','disabled', or 'approved'")
	
	if not utils.validate_uuid(wid):
		return RetVal(BadParameterValue, 'bad wid')

	conn.send_message({
		'Action' : 'SETSTATUS',
		'Data' : {
			'Workspace-ID': wid,
			'Status': status
		}
	})
	response = conn.read_response(server_response)
	if response['Code'] != 200:
		return wrap_server_error(response)

	return RetVal()
Пример #9
0
    def is_valid(self) -> bool:
        '''Returns true if data stored in the profile object is valid'''
        if self.name and utils.validate_uuid(self.id):
            return True

        return False
Пример #10
0
def test_validate_uuid():
    '''Tests utils.validate_uuid'''
    assert utils.validate_uuid(
        '5a56260b-aa5c-4013-9217-a78f094432c3'), 'Failed to validate good ID'
    assert not utils.validate_uuid(
        '5a56260b-c-4013-9217-a78f094432c3'), 'Failed to reject bad ID'