Beispiel #1
0
    def save(self, data):
        file_name = data['fileName']
        file_name = file_name.strip()

        if file_name not in self.assignment.src or file_name.endswith('.ok'):
            if file_name != 'submit':
                logging.warning("Unknown filename {}".format(file_name))
                print_error("Unknown file - Not saving {}".format(file_name))
                return

        if not os.path.isfile(file_name):
            log.warning('File {} does not exist. Not backing up'.format(file_name))
            backup_dst = file_name
        else:
            # Backup the file
            log.debug("Backing up file")
            backup_dst = self.backup_file(file_name)
            print_success("Backed up file to {}".format(backup_dst))

        log.debug("Beginning overwriting file")
        contents = data['file']
        with open(file_name, 'w') as f:
            f.write(contents)
        log.debug("Done replacing file")

        # Update file contents for backup
        self.file_contents[file_name] = contents

        return backup_dst
Beispiel #2
0
def check_version(server, version, filename, timeout=SHORT_TIMEOUT):
    """Check for the latest version of OK and update accordingly."""

    address = VERSION_ENDPOINT.format(server=server)

    log.info('Checking for software updates...')
    log.info('Existing OK version: %s', version)
    log.info('Checking latest version from %s', address)

    try:
        response = requests.get(address, timeout=timeout)
        response.raise_for_status()
    except (requests.exceptions.RequestException,
            requests.exceptions.BaseHTTPError) as e:
        print_error('Network error when checking for updates.')
        log.warning('Network error when checking version from %s: %s',
                    address,
                    str(e),
                    stack_info=True)
        return False

    response_json = response.json()
    if not _validate_api_response(response_json):
        print_error('Error while checking updates: malformed server response')
        log.info('Malformed response from %s: %s', address, response.text)
        return False

    current_version = response_json['data']['results'][0]['current_version']
    if current_version == version:
        print_success('OK is up to date')
        return True

    download_link = response_json['data']['results'][0]['download_link']

    log.info('Downloading version %s from %s', current_version, download_link)

    try:
        response = requests.get(download_link, timeout=timeout)
        response.raise_for_status()
    except (requests.exceptions.RequestException,
            requests.exceptions.BaseHTTPError) as e:
        print_error('Error when downloading new version of OK')
        log.warning('Error when downloading new version of OK: %s',
                    str(e),
                    stack_info=True)
        return False

    log.info('Writing new version to %s', filename)

    zip_binary = response.content
    try:
        _write_zip(filename, zip_binary)
    except IOError as e:
        print_error('Error when downloading new version of OK')
        log.warning('Error writing to %s: %s', filename, str(e))
        return False
    else:
        print_success('Updated to version: {}'.format(current_version))
        log.info('Successfully wrote to %s', filename)
        return True
Beispiel #3
0
 def decrypt(self, keys):
     decrypted_files, undecrypted_files = self.attempt_decryption(keys)
     if not undecrypted_files + decrypted_files:
         print_success("All files are decrypted")
     elif undecrypted_files:
         if keys:
             print_error("Unable to decrypt some files with the keys", ", ".join(keys))
         else:
             print_error("No keys found, could not decrypt any files")
         print_error("    Non-decrypted files:", *undecrypted_files)
Beispiel #4
0
 def decrypt(ciphertext):
     if not encryption.is_encrypted(ciphertext):
         return ciphertext
     try:
         plaintext = encryption.decrypt(ciphertext, key)
         nonlocal success
         success = True
         print_success("decrypted", path, "with", key)
         return plaintext
     except encryption.InvalidKeyException:
         return ciphertext
Beispiel #5
0
    def run(self, messages, nointeract=False):
        if not self.assignment.endpoint:
            log.info('No assignment endpoint, skipping backup')
            return

        if self.args.local:
            print_warning("Cannot backup when running ok with --local.")
            return

        if not self.args.insecure:
            network.check_ssl()

        if self.args.revise:
            action = 'revision'
        elif self.args.submit:
            action = 'submission'
        else:
            action = 'backup'

        message_list = self.load_unsent_messages()

        access_token = self.assignment.authenticate(nointeract=nointeract)
        log.info('Authenticated with access token')
        log.info('Sending unsent messages')

        if not access_token:
            print_error(
                "Not authenticated. Cannot send {} to server".format(action))
            self.dump_unsent_messages(message_list)
            return

        # Messages from the current backup to send first
        is_send_first = self.args.submit or self.args.revise
        subm_messages = [messages] if is_send_first else []

        if is_send_first:
            response = self.send_all_messages(access_token,
                                              subm_messages,
                                              current=True)
            if message_list:
                self.send_all_messages(access_token,
                                       message_list,
                                       current=False)
        else:
            message_list.append(messages)
            response = self.send_all_messages(access_token,
                                              message_list,
                                              current=False)

        base_url = self.assignment.server_url + '/{}/{}/{}'

        if isinstance(response, dict):
            print_success('{action} successful for user: {email}'.format(
                action=action.title(), email=response['data']['email']))

            submission_type = 'submissions' if self.args.submit else 'backups'
            url = base_url.format(response['data']['assignment'],
                                  submission_type, response['data']['key'])

            if self.args.submit or self.args.backup:
                print_success('URL: {0}'.format(url))

            if self.args.backup:
                print('NOTE: this is only a backup. '
                      'To submit your assignment, use:\n'
                      '\tpython3 ok --submit')

        self.dump_unsent_messages(message_list + subm_messages)
        print()
Beispiel #6
0
    def start_firebase(self, messages):
        access_token = self.assignment.authenticate()
        email = self.assignment.get_student_email()
        identifier = self.assignment.get_identifier()

        firebase = pyrebase.initialize_app(self.FIREBASE_CONFIG)
        self.fire_auth = firebase.auth()
        self.fire_db = firebase.database()

        self.user_email = email
        self.hostname = platform.node()

        data = {
            'access_token': access_token,
            'email': email,
            'identifier': identifier,
            'assignment': self.assignment.endpoint,
            'file_contents': messages.get('file_contents'),
            'analytics': messages.get('analytics'),
        }

        # Check for existing sessions first - TBD Future
        # existing_sessions = self.send_messages(data, endpoint='/collab/list')
        # response = self.prompt_for_existing_session(existing_sessions.get('sessions'))
        # if response:
        #     data['desired_session'] = response

        # Send data to collaborate server
        response_data = self.send_messages(data, self.LONG_TIMEOUT)
        if 'error' in response_data or 'session' not in response_data:
            print_error("There was an error while starting the session: {} Try again later"
                  .format(response_data.get('error')))
            log.warning("Error: {}".format(response_data.get('error')))
            return

        self.session_id = response_data['session']
        self.short_url = response_data['short_url']
        self.login_user = response_data.get('login_user')

        # Login as the firebase user
        email, password = response_data.get('login_user'), response_data.get('password')

        try:
            self.fire_user = self.fire_auth.sign_in_with_email_and_password(email,
                                                                            password)
            self.fire_uid = self.fire_user['localId']
        except (ValueError, KeyError) as e:
            log.warning("Could not login", exc_info=True)
            print_error("Could not login to the collaboration server.")
            return

        self.stream = (self.get_firebase()
                           .child('actions').stream(self.stream_listener,
                                                    self.fire_user['idToken']))

        self.presence = (self.get_firebase()
                             .child('clients').push({'computer': platform.node(),
                                                     'uid': self.fire_uid,
                                                     'owner': self.user_email,
                                                     'email': self.user_email},
                                                    self.fire_user['idToken']))

        # Parse response_url
        if response_data:
            open_url = response_data['url']
            if 'access_token' not in open_url:
                open_url = open_url + "?access_token={}".format(access_token)
            could_open = webbrowser.open_new(open_url)
            if not could_open:
                print("Could not open browser. Go to {}".format(open_url))
        else:
            log.error("There was an error with the server. Please try again later!")
            return

        print_success("Tell your group members or course staff to go to {}"
              .format(self.short_url))

        while True:
            data = input("[{}] Type exit to disconnect: ".format(self.short_url))
            if data.strip().lower() == 'exit':
                raise ValueError('Done with session')