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
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
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)
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
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()
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')