Esempio n. 1
0
def patient_data_change(event, staff, meeting, roles):
    """
    Handles PATIENT_DATA_CHANGE event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    log.debug("Processing PDC event")
    # Check whether they should be allowed to start discussion
    if Role.HOST not in roles:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.UNAUTHORISED,
                                        details=''))

    # Check if meeting actually started
    ok, err_ack = validate_meeting_started(event, meeting)
    if not ok:
        return False, err_ack

    # Check if they have actually joined
    ok, err_ack = validate_join(event, staff, meeting)
    if not ok:
        return False, err_ack

    # Check of ref event is correct
    ok, err_ack = validate_ref_event(event, meeting)
    if not ok:
        return False, err_ack

    # Parsing content as VoteContent
    try:
        pdc = PDCContent.parse(event.content)
    except KeyError as ke:
        traceback.print_tb(ke.__traceback__)
        log.error(ke)
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(
                error_code=EventError.MALFORMED_EVENT,
                details="Content doesnt have sufficient values"))

    # Check if patient actually exists
    patient_id = pdc.patient
    patient = db.get_patient(patient_id)
    if patient is None:
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(error_code=EventError.PATIENT_NOT_FOUND,
                                    details=''))

    # ACK
    ack = get_ack(event.id, meeting.id)
    return True, ack
Esempio n. 2
0
def poll(event, staff, meeting, roles):
    """
    Handles the POLL event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    log.debug("Processing Poll event")
    # Check whether they should be allowed to start a poll
    if Role.HOST not in roles:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.UNAUTHORISED,
                                        details=''))

    # Check if meeting actually started
    ok, err_ack = validate_meeting_started(event, meeting)
    if not ok:
        return False, err_ack

    # Check if they have actually joined
    ok, err_ack = validate_join(event, staff, meeting)
    if not ok:
        return False, err_ack

    # Check of ref event is correct
    ok, err_ack = validate_ref_event(event, meeting)
    if not ok:
        return False, err_ack

    # Get Meeting session details
    meeting_session_details = ongoing_meetings.get(
        meeting.id, None)  # type: OngoingMeeting

    # Parsing content as PollContent
    try:
        pc = PollContent.parse(event.content)
    except KeyError as ke:
        log.error(ke)
        traceback.print_tb(ke.__traceback__)
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(
                error_code=EventError.MALFORMED_EVENT,
                details="Content doesnt have sufficient values"))

    new_poll = Poll()
    poll.votes = {}

    meeting_session_details.polls[event.id] = new_poll

    # ACK
    ack = get_ack(event.id, event.meeting_id)
    return True, ack
Esempio n. 3
0
def validate_signature(event,
                       staff,
                       meeting,
                       check_contract=False) -> (bool, dict):
    """
    Validates the signature of an event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    log.debug('Validating Signature...')

    sig_addr = str(auth.get_sig_address_from_event(event.to_json_dict()))

    #  Check session key, or if it doesnt exist, check with actual public key in smart contract
    ok = False
    if check_contract:
        log.debug('Checking DeeId Contract')
        ok = auth.ethkey_in_deeid_contract(sig_addr, staff.id)
        log.debug('Eth key in contract? ' + str(ok))
    else:
        # Get Meeting session details to get the session key
        meeting_session_details = ongoing_meetings.get(
            meeting.id, None)  # type: OngoingMeeting
        meeting_session_key = None
        if meeting_session_details is not None:
            meeting_session_key = meeting_session_details.session_keys.get(
                staff.id, None)

        if meeting_session_key is None:
            err_event = get_error_ack(
                event.id,
                event.meeting_id,
                content=AckErrorContent(
                    error_code=EventError.BAD_SESSION_KEY_SIGNATURE,
                    details=''))
            return False, err_event

        ok = sig_addr.lower() == meeting_session_key.lower()
        log.debug('Sig Addr ' + sig_addr)
        log.debug('Session key ' + meeting_session_key)
        log.debug('Session key matches up? ' + str(ok))

    if not ok:
        err_event = get_error_ack(event.id,
                                  event.meeting_id,
                                  content=AckErrorContent(
                                      error_code=EventError.BAD_SIGNATURE,
                                      details=''))

        return False, err_event

    return True, None
Esempio n. 4
0
def end_poll(event, staff, meeting, roles):
    """
    Handles END_POLL event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    log.debug("Processing End Poll event")
    # Check whether they should be allowed to end poll
    if Role.HOST not in roles:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.UNAUTHORISED,
                                        details=''))

    # Check if meeting actually started
    ok, err_ack = validate_meeting_started(event, meeting)
    if not ok:
        return False, err_ack

    # Check if they have actually joined
    ok, err_ack = validate_join(event, staff, meeting)
    if not ok:
        return False, err_ack

    # Get Meeting session details
    meeting_session_details = ongoing_meetings.get(
        meeting.id, None)  # type: OngoingMeeting

    #  Check if refEvent is a poll
    poll = meeting_session_details.polls.get(event.ref_event, None)
    if poll is None:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.POLL_NOT_FOUND,
                                        details=''))

    vote_event_ids = [event.id for event in list(poll.votes.values())]
    poll_end_ack_event = AckPollEndContent(votes=vote_event_ids)

    # ACK
    ack = get_ack(event.id,
                  meeting.id,
                  type=MeetingEventType.ACK_POLL_END,
                  content=poll_end_ack_event)

    # Delete poll
    meeting_session_details.polls.pop(event.ref_event)

    return True, ack
Esempio n. 5
0
def discussion(event, staff, meeting, roles):
    """
    Handles the DISCUSSION event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    log.debug("Processing Discussion event")
    # Check whether they should be allowed to start discussion
    if Role.HOST not in roles:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.UNAUTHORISED,
                                        details=''))

    # Check if meeting actually started
    ok, err_ack = validate_meeting_started(event, meeting)
    if not ok:
        return False, err_ack

    # Check if they have actually joined
    ok, err_ack = validate_join(event, staff, meeting)
    if not ok:
        return False, err_ack

    # Check of ref event is correct
    ok, err_ack = validate_ref_event(event, meeting)
    if not ok:
        return False, err_ack

    # ACK
    ack = get_ack(event.id, meeting.id)
    return True, ack
Esempio n. 6
0
def comment_reply_disagreement(event, staff, meeting, roles):
    """
    Handles COMMENT and REPLY and DISAGREEMENT event as they have the same protocol
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    log.debug("Processing Comment/Reply/Disagreement event")
    # Check whether they should be allowed to vote
    if Role.PARTICIPANT not in roles:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.UNAUTHORISED,
                                        details=''))

    # Check if meeting actually started
    ok, err_ack = validate_meeting_started(event, meeting)
    if not ok:
        return False, err_ack

    # Check if they have actually joined
    ok, err_ack = validate_join(event, staff, meeting)
    if not ok:
        return False, err_ack

    # Check of ref event is correct
    ok, err_ack = validate_ref_event(event, meeting)
    if not ok:
        return False, err_ack

    # ACK
    ack = get_ack(event.id, meeting.id)
    return True, ack
Esempio n. 7
0
def end_meeting_session(meeting, event, signed_ack_event):
    """
    Gracefully ends a meeting by populating smart contract and the database
    """
    # Write the event hash of the meeting to smart contract  - COSTS MONEY
    meeting_session_details = ongoing_meetings.get(
        meeting.id, None)  # type: OngoingMeeting
    try:
        start_hash = meeting_session_details.start_event.id
        end_hash = signed_ack_event.id
        smart_contract.set_event_hash(meeting, start_hash, end_hash)
    except Exception as e:  # We catch all exceptions as there are too many
        log.error(e)
        traceback.print_tb(e.__traceback__)
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.INTERNAL_ERROR,
                                        details=''))

    # Mark meeting as ended
    meeting.ended = True
    db.update_meeting(meeting.id, meeting.to_json_dict())

    print('============= MEETING END =============')
    print(ongoing_meetings[meeting.id])
    print(signed_ack_event)
    ongoing_meetings.pop(meeting.id)
    close_room(meeting.id)
Esempio n. 8
0
def validate_preliminary_authority(event, roles) -> (bool, dict):
    """
    Does preliminary checks to see if the user is authorised to post the event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    if not roles:
        err_event = get_error_ack(event.id,
                                  event.meeting_id,
                                  content=AckErrorContent(
                                      error_code=EventError.UNAUTHORISED,
                                      details=''))

        return False, err_event
    return True, None
Esempio n. 9
0
def validate_join(event, staff, meeting) -> (bool, dict):
    """
    Validates if a staff has joined the meeting or not
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    joined = staff.id in meeting.attended_staff
    if not joined:
        err_ack = get_error_ack(event.id,
                                event.meeting_id,
                                content=AckErrorContent(
                                    error_code=EventError.MEETING_NOT_JOINED,
                                    details=''))
        return False, err_ack

    return True, None
Esempio n. 10
0
def validate_meeting_started(event: Event, meeting: Meeting) -> (bool, dict):
    """
    Validates if a meeting has started or not
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    meeting_started = meeting.id in ongoing_meetings
    if not meeting_started:
        err_ack = get_error_ack(event.id,
                                event.meeting_id,
                                content=AckErrorContent(
                                    error_code=EventError.MEETING_NOT_STARTED,
                                    details=''))
        return False, err_ack

    return True, None
Esempio n. 11
0
def validate_schema(event_dict) -> (bool, dict):
    """
    Validates the schema using JSON Schema
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    ok, err = event_schema_validator.validate(event_dict)
    if not ok:
        err_event = get_error_ack("unknown",
                                  "unknown",
                                  content=AckErrorContent(
                                      error_code=EventError.MALFORMED_EVENT,
                                      details=err))

        return False, err_event

    return True, None
Esempio n. 12
0
def validate_ref_event(event, meeting) -> (bool, dict):
    """
    Validates a reference event (checks if it exists)
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    meeting_session_details = ongoing_meetings.get(
        meeting.id, None)  # type: OngoingMeeting
    ref_valid = event.ref_event in meeting_session_details.events

    if not ref_valid:
        err_ack = get_error_ack(event.id,
                                event.meeting_id,
                                content=AckErrorContent(
                                    error_code=EventError.INVALID_REF_EVENT,
                                    details=''))
        return False, err_ack
    return True, None
Esempio n. 13
0
def validate_timestamp(event) -> (bool, dict):
    """
    Validates the timestamp of an event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    current_time = int(time.time())
    if not (current_time - timestamp_tolerance <= event.timestamp <=
            current_time + timestamp_tolerance):
        err_event = get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(error_code=EventError.TIMESTAMP_NOT_SYNC,
                                    details='Server Timestamp : ' +
                                    str(current_time)))

        return False, err_event

    return True, None
Esempio n. 14
0
def end(event, staff, meeting, roles):
    """
    Handles the END event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    log.debug("Processing End event")
    # Check whether they should be allowed to end
    if Role.HOST not in roles:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.UNAUTHORISED,
                                        details=''))

    # Check if meeting actually started
    ok, err_ack = validate_meeting_started(event, meeting)
    if not ok:
        return False, err_ack

    # Check if they have actually joined
    ok, err_ack = validate_join(event, staff, meeting)
    if not ok:
        return False, err_ack

    # Check if ref event is correct
    ok, err_ack = validate_ref_event(event, meeting)
    if not ok:
        return False, err_ack

    # Get Meeting session details
    meeting_session_details = ongoing_meetings.get(
        meeting.id, None)  # type: OngoingMeeting

    # ACK  -- WE get ACK early as we need the signature for smart contract later, and there could be errors with that
    eac = AckEndContent(list(meeting_session_details.unref_events.keys()))
    ack = get_ack(event.id,
                  event.meeting_id,
                  type=MeetingEventType.ACK_END,
                  content=eac)
    return True, ack
Esempio n. 15
0
def start(event, staff, meeting, roles) -> (bool, dict):
    """
    Handles the START event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    log.debug("Processing Start event")
    # Check if the user is allowed to start
    if Role.HOST not in roles:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.UNAUTHORISED,
                                        details=''))

    # Check if meeting has already started, if it has send the otp, in case the host has forgotten
    started, _ = validate_meeting_started(event, meeting)
    if started:
        otp = ongoing_meetings[meeting.id].otp
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(
                error_code=EventError.MEETING_ALREADY_STARTED,
                details='Meeting already started, otp : ' + otp))

    # Parse the content of event as StartContent
    try:
        sc = StartContent.parse(event.content)
        dee_id_login_sig = DeeIdLoginSigSigned.parse(sc.deeid_login_sig_signed)
        new_key = sc.key
        uid = dee_id_login_sig.uid
        expiry = dee_id_login_sig.expiry_time
        sig = dee_id_login_sig.signature
    except KeyError as ke:
        log.error(ke)
        traceback.print_tb(ke.__traceback__)
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(
                error_code=EventError.MALFORMED_EVENT,
                details="Content doesnt have sufficient values"))

    # Authenticate new key
    msg = uid + staff.id + expiry + new_key
    addr = auth.get_sig_address_from_signature(msg=msg, signature=sig)
    ok = auth.ethkey_in_deeid_contract(addr, staff.id)
    if not ok:
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(
                error_code=EventError.UNAUTHORISED,
                details="New pubKey cannot be authenticated"))
    print("OTP: ", sc.otp)
    #  Create new meeting session
    om = OngoingMeeting()
    om.otp = sc.otp
    om.host = staff.id
    om.start_event = event
    om.events = {event.id: event}
    om.polls = {}
    om.unref_events = {}
    om.session_keys = {staff.id: new_key}
    om.latest_join_events = []

    # Create smart contract for the meeting  - COSTS MONEY
    log.debug("Deploying Smart Contract...")
    try:
        meeting.contract_id = smart_contract.new_meeting_contract(meeting)
    except Exception as e:  # We catch all exceptions as there are too many
        log.error("FAILED deploying smart contract")
        log.error(e)
        traceback.print_tb(e.__traceback__)
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(
                error_code=EventError.INTERNAL_ERROR,
                details='Smart Contract could not be deployed'))

    log.debug("Deployed smart contract!")
    log.debug(meeting.contract_id)
    ongoing_meetings[meeting.id] = om

    meeting.started = True  # Set the meeting as started in the db
    meeting.start_event_id = event.id  # Set the start event
    db.update_meeting(meeting.id, meeting.to_json_dict())

    # ACK
    ack = get_ack(event.id, event.meeting_id)
    return True, ack
Esempio n. 16
0
def vote(event, staff, meeting, roles):
    """
    Handles the VOTE event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    log.debug("Processing Vote Event")
    # Check whether they should be allowed to vote
    if Role.PARTICIPANT not in roles:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.UNAUTHORISED,
                                        details=''))

    # Check if meeting actually started
    ok, err_ack = validate_meeting_started(event, meeting)
    if not ok:
        return False, err_ack

    # Check if they have actually joined
    ok, err_ack = validate_join(event, staff, meeting)
    if not ok:
        return False, err_ack

    # Get Meeting session details
    meeting_session_details = ongoing_meetings.get(
        meeting.id, None)  # type: OngoingMeeting

    # Check if refEvent is a poll
    poll = meeting_session_details.polls.get(event.ref_event, None)
    if poll is None:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.POLL_NOT_FOUND,
                                        details=''))

    # Parsing content as VoteContent
    try:
        vc = VoteContent.parse(event.content)
    except KeyError as ke:
        traceback.print_tb(ke.__traceback__)
        log.error(ke)
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(
                error_code=EventError.MALFORMED_EVENT,
                details="Content doesnt have sufficient values"))

    # Check if already voted
    if event.by in poll.votes:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.ALREADY_VOTED,
                                        details=''))

    log.debug("Adding the vote to votes")
    poll.votes[staff.id] = event

    # ACK
    ack = get_ack(event.id, event.meeting_id)
    return True, ack
Esempio n. 17
0
def room_message(event_string):
    """
    Main function that handles all events that enter through the web socket
    """
    # Parse json as dict
    try:
        event_json = json.loads(event_string)
    except ValueError as ve:
        log.error("Error Parsing room-message as JSON!")
        log.error(ve)
        traceback.print_tb(ve.__traceback__)
        return json.dumps(
            sign(
                get_error_ack(
                    "unknown",
                    "unknown",
                    content=AckErrorContent(
                        error_code=EventError.MALFORMED_EVENT,
                        details='Cant parse message as JSON'))).to_json_dict())

    # Validate JSON dict using schema
    ok, err_event = validate_schema(event_json)
    if not ok:
        log.error("Sending error msg")
        errormsg = json.dumps(sign(err_event).to_json_dict())
        log.error("======== error_msg: " + errormsg)
        return errormsg

    # Parse dict as event object
    try:
        event = Event.parse(event_json)
    except KeyError as ve:
        log.error("Error Parsing room-message!")
        log.error(ve)
        traceback.print_tb(ve.__traceback__)
        return json.dumps(
            sign(
                get_error_ack("unknown",
                              "unknown",
                              content=AckErrorContent(
                                  error_code=EventError.MALFORMED_EVENT,
                                  details='Cant parse message as Event'))).
            to_json_dict())

    # Check timestamp
    ok, err_event = validate_timestamp(event)
    if not ok:
        return json.dumps(sign(err_event).to_json_dict())

    # Get the staff
    try:
        staff = Staff.parse(db.get_staff(event.by))
    except KeyError as ke:
        log.error(ke)
        traceback.print_tb(ke.__traceback__)
        return json.dumps(
            sign(
                get_error_ack(event.id,
                              event.meeting_id,
                              content=AckErrorContent(
                                  error_code=EventError.STAFF_NOT_FOUND,
                                  details=''))).to_json_dict())
    except TypeError as te:
        log.error(te)
        traceback.print_tb(te.__traceback__)
        return json.dumps(
            sign(
                get_error_ack(event.id,
                              event.meeting_id,
                              content=AckErrorContent(
                                  error_code=EventError.STAFF_NOT_FOUND,
                                  details=''))).to_json_dict())

    # Get the meeting
    try:
        meeting = Meeting.parse(db.get_meeting(event.meeting_id))
    except KeyError as ke:
        log.error(ke)
        traceback.print_tb(ke.__traceback__)
        return json.dumps(
            sign(
                get_error_ack(event.id,
                              event.meeting_id,
                              content=AckErrorContent(
                                  error_code=EventError.MEETING_NOT_FOUND,
                                  details=''))).to_json_dict())

    except TypeError as te:
        log.error(te)
        traceback.print_tb(te.__traceback__)
        return json.dumps(
            sign(
                get_error_ack(event.id,
                              event.meeting_id,
                              content=AckErrorContent(
                                  error_code=EventError.MEETING_NOT_FOUND,
                                  details=''))).to_json_dict())

    # Check signature, before trusting anything it says

    if event.type in [MeetingEventType.JOIN, MeetingEventType.START
                      ]:  # We check contract for join and start
        ok, err_event = validate_signature(event,
                                           staff,
                                           meeting,
                                           check_contract=True)
        if not ok:
            return json.dumps(sign(err_event).to_json_dict())
    else:
        ok, err_event = validate_signature(event, staff, meeting)
        if not ok:
            return json.dumps(sign(err_event).to_json_dict())

    # Get the roles
    roles = get_role(staff, meeting)

    # A preliminary authority check to see if the user can make any statements about the meeting
    ok, err_event = validate_preliminary_authority(event, roles)
    if not ok:
        return json.dumps(sign(err_event).to_json_dict())

    # Get the event type
    event_type = MeetingEventType(event.type)
    ack_event = None
    ok = False
    end_meeting = False
    send_privately = False

    if event_type == MeetingEventType.START:
        ok, ack_event = start(event, staff, meeting, roles)

    if event_type == MeetingEventType.JOIN:
        ok, ack_event = join(event, staff, meeting, roles)

    if event_type == MeetingEventType.LEAVE:
        ok, ack_event = leave(event, staff, meeting)

    if event_type == MeetingEventType.POLL:
        ok, ack_event = poll(event, staff, meeting, roles)

    if event_type == MeetingEventType.VOTE:
        ok, ack_event = vote(event, staff, meeting, roles)

    if event_type == MeetingEventType.POLL_END:
        ok, ack_event = end_poll(event, staff, meeting, roles)

    if event_type == MeetingEventType.COMMENT or event_type == MeetingEventType.REPLY or event_type == MeetingEventType.DISAGREEMENT:
        ok, ack_event = comment_reply_disagreement(event, staff, meeting,
                                                   roles)

    if event_type == MeetingEventType.DISCUSSION:
        ok, ack_event = discussion(event, staff, meeting, roles)

    if event_type == MeetingEventType.PATIENT_DATA_CHANGE:
        ok, ack_event = patient_data_change(event, staff, meeting, roles)

    if event_type == MeetingEventType.END:
        ok, ack_event = end(event, staff, meeting, roles)
        if ok:
            end_meeting = True

    if not ok:  # If not ok we send the error ack event privately
        return json.dumps(sign(ack_event).to_json_dict())
    else:
        # If an event has been referenced
        check_and_remove_ref_event(meeting, event.ref_event)

        # Add ack and event to unreferenced events
        add_event_as_unref(meeting, event)
        add_event_as_unref(meeting, ack_event)

        # Sign the ack
        signed_ack_event = sign(ack_event)

        if not send_privately:  # Only Broadcast if the send_privately is set to False
            # Broadcast event
            send(json.dumps(event.to_json_dict()), broadcast_room=meeting.id)
            send(json.dumps(signed_ack_event.to_json_dict()),
                 broadcast_room=meeting.id)

        record(event, meeting)
        record(signed_ack_event, meeting)

        if end_meeting:
            end_meeting_session(meeting, event, signed_ack_event)

        # Send the ack event to the user privately as well
        return json.dumps(signed_ack_event.to_json_dict())
Esempio n. 18
0
def join(event, staff, meeting, roles) -> (bool, dict):
    """
    Handles the JOIN event
    :return: returns a tuple of (bool, dict). The bool is if the execution was ok,
    dict returns the error event in case the execution failed
    """
    log.debug("Processing Join event")
    # Check if the user is allowed to join
    if Role.PARTICIPANT not in roles:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.UNAUTHORISED,
                                        details=''))

    # Check if meeting has started
    ok, err_ack = validate_meeting_started(event, meeting)
    if not ok:
        return False, err_ack

    # Get Meeting session details
    meeting_session_details = ongoing_meetings.get(
        meeting.id, None)  # type: OngoingMeeting

    # Check if ref event is a start event
    if event.ref_event != meeting_session_details.start_event.id:
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(
                error_code=EventError.INVALID_REF_EVENT,
                details='Ref Event must be the Start event'))

    # Parse the content of event as JoinContent
    try:
        jc = JoinContent.parse(event.content)
        dee_id_login_sig = DeeIdLoginSigSigned.parse(jc.deeid_login_sig_signed)
        new_key = jc.key
        uid = dee_id_login_sig.uid
        expiry = dee_id_login_sig.expiry_time
        sig = dee_id_login_sig.signature
    except KeyError as ke:
        log.error(ke)
        traceback.print_tb(ke.__traceback__)
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(
                error_code=EventError.MALFORMED_EVENT,
                details="Content doesnt have sufficient values"))

    # Check OTP
    if not jc.otp == meeting_session_details.otp:
        return False, get_error_ack(event.id,
                                    event.meeting_id,
                                    content=AckErrorContent(
                                        error_code=EventError.BAD_OTP,
                                        details=''))

    # Authenticate new key
    msg = uid + staff.id + expiry + new_key
    addr = auth.get_sig_address_from_signature(msg=msg, signature=sig)
    ok = auth.ethkey_in_deeid_contract(addr, staff.id)

    if not ok:
        return False, get_error_ack(
            event.id,
            event.meeting_id,
            content=AckErrorContent(
                error_code=EventError.UNAUTHORISED,
                details="New pubKey cannot be authenticated"))

    meeting_session_details.session_keys[staff.id] = new_key

    # Add them to the list of staff that have joined the meeting
    update_attended_staff(meeting, staff)

    # Join the socketio room using the sessison_id
    join_room(meeting.id)

    start_event = meeting_session_details.start_event
    latest_join_events = meeting_session_details.latest_join_events

    # ACK
    jac = AckJoinContent(start_event, latest_join_events)
    ack = get_ack(event.id,
                  event.meeting_id,
                  type=MeetingEventType.ACK_JOIN,
                  content=jac)
    return True, ack