Ejemplo n.º 1
0
    def __init__(self, db_wrapper: DbWrapper, args, mapping_manager: MappingManager, websocket: WebsocketServer, logger,
                 app, device_updater):
        self._db: DbWrapper = db_wrapper
        self._args = args
        if self._args.madmin_time == "12":
            self._datetimeformat = '%Y-%m-%d %I:%M:%S %p'
        else:
            self._datetimeformat = '%Y-%m-%d %H:%M:%S'
        self._adb_connect = ADBConnect(self._args)
        self._device_updater = device_updater

        self._mapping_manager: MappingManager = mapping_manager

        self._ws_server: WebsocketServer = websocket
        self._ws_connected_phones: list = []
        self._logger = logger
        self._app = app
Ejemplo n.º 2
0
 def __init__(self, db, args, logger, app, mapping_manager: MappingManager, data_manager):
     self._db = db
     self._args = args
     if self._args.madmin_time == "12":
         self._datetimeformat = '%Y-%m-%d %I:%M:%S %p'
     else:
         self._datetimeformat = '%Y-%m-%d %H:%M:%S'
     self._adb_connect = ADBConnect(self._args)
     self._ws_connected_phones: list = []
     self._logger = logger
     self._data_manager = data_manager
     self._app = app
     self._app.config["TEMPLATES_AUTO_RELOAD"] = True
     cache.init_app(self._app)
     self._mapping_mananger = mapping_manager
Ejemplo n.º 3
0
class control(object):
    def __init__(self, db_wrapper: DbWrapper, args,
                 mapping_manager: MappingManager, websocket: WebsocketServer,
                 logger, app, deviceUpdater):
        self._db: DbWrapper = db_wrapper
        self._args = args
        if self._args.madmin_time == "12":
            self._datetimeformat = '%Y-%m-%d %I:%M:%S %p'
        else:
            self._datetimeformat = '%Y-%m-%d %H:%M:%S'
        self._adb_connect = ADBConnect(self._args)
        self._device_updater = deviceUpdater

        self._mapping_manager: MappingManager = mapping_manager

        self._ws_server: WebsocketServer = websocket
        self._ws_connected_phones: list = []
        self._logger = logger
        self._app = app
        self.add_route()

    def add_route(self):
        routes = [
            ("/devicecontrol", self.get_phonescreens),
            ("/take_screenshot", self.take_screenshot),
            ("/click_screenshot", self.click_screenshot),
            ("/swipe_screenshot", self.swipe_screenshot),
            ("/quit_pogo", self.quit_pogo),
            ("/restart_phone", self.restart_phone),
            ("/clear_game_data", self.clear_game_data),
            ("/send_gps", self.send_gps),
            ("/send_text", self.send_text),
            ("/upload", self.upload),
            ("/send_command", self.send_command),
            ("/get_uploaded_files", self.get_uploaded_files),
            ("/uploaded_files", self.uploaded_files),
            ("/delete_file", self.delete_file),
            ("/install_file", self.install_file),
            ("/get_install_log", self.get_install_log),
            ("/delete_log_entry", self.delete_log_entry),
            ("/install_status", self.install_status),
            ("/install_file_all_devices", self.install_file_all_devices),
            ("/restart_job", self.restart_job),
            ("/delete_log", self.delete_log),
            ("/get_all_workers", self.get_all_workers),
            ("/job_for_worker", self.job_for_worker),
            ("/reload_jobs", self.reload_jobs),
        ]
        for route, view_func in routes:
            self._app.route(route, methods=['GET', 'POST'])(view_func)

    @auth_required
    @nocache
    @logger.catch()
    def get_phonescreens(self):
        if not os.path.exists(
                os.path.join(mapadroid.MAD_ROOT, self._args.temp_path,
                             "madmin")):
            os.makedirs(os.path.join(self._args.temp_path, "madmin"))

        screens_phone = []
        ws_connected_phones = []
        if self._ws_server is not None:
            phones = self._ws_server.get_reg_origins()
        else:
            phones = []
        devicemappings = self._mapping_manager.get_all_devicemappings()

        # Sort devices by name.
        phones = sorted(phones)
        for phonename in phones:
            ws_connected_phones.append(phonename)
            add_text = ""
            adb_option = False
            adb = devicemappings.get(phonename, {}).get('adb', False)
            if adb is not None and self._adb_connect.check_adb_status(
                    adb) is not None:
                self._ws_connected_phones.append(adb)
                adb_option = True
                add_text = '<b>ADB</b>'
            else:
                self._ws_connected_phones.append(adb)

            filename = generate_device_screenshot_path(phonename,
                                                       devicemappings,
                                                       self._args)
            try:
                screenshot_ending: str = ".jpg"
                image_resize(filename,
                             os.path.join(self._args.temp_path, "madmin"),
                             width=250)
                screen = "screenshot/madmin/screenshot_" + str(
                    phonename) + screenshot_ending
                screens_phone.append(
                    generate_phones(phonename,
                                    add_text,
                                    adb_option,
                                    screen,
                                    filename,
                                    self._datetimeformat,
                                    dummy=False))
            except IOError:
                screen = "static/dummy.png"
                screens_phone.append(
                    generate_phones(phonename,
                                    add_text,
                                    adb_option,
                                    screen,
                                    filename,
                                    self._datetimeformat,
                                    dummy=True))
                try:
                    os.remove(filename)
                    self._logger.info(
                        "Screenshot {} was corrupted and has been deleted",
                        filename)
                except:
                    pass

        for phonename in self._adb_connect.return_adb_devices():
            if phonename.serial not in self._ws_connected_phones:
                devicemappings = self._mapping_manager.get_all_devicemappings()
                for pho in devicemappings:
                    if phonename.serial == devicemappings[pho].get(
                            'adb', False):
                        adb_option = True
                        add_text = '<b>ADB - no WS <i class="fa fa-exclamation-triangle"></i></b>'
                        filename = generate_device_screenshot_path(
                            pho, devicemappings, self._args)
                        if os.path.isfile(filename):
                            image_resize(filename,
                                         os.path.join(mapadroid.MAD_ROOT,
                                                      self._args.temp_path,
                                                      "madmin"),
                                         width=250)
                            screenshot_ending: str = ".jpg"
                            screen = "screenshot/madmin/screenshot_" + str(
                                pho) + screenshot_ending
                            screens_phone.append(
                                generate_phones(pho,
                                                add_text,
                                                adb_option,
                                                screen,
                                                filename,
                                                self._datetimeformat,
                                                dummy=False))
                        else:
                            screen = "static/dummy.png"
                            screens_phone.append(
                                generate_phones(pho,
                                                add_text,
                                                adb_option,
                                                screen,
                                                filename,
                                                self._datetimeformat,
                                                dummy=True))

        return render_template('phonescreens.html',
                               editform=screens_phone,
                               header="Device control",
                               title="Device control")

    @auth_required
    def take_screenshot(self, origin=None, adb=False):
        origin = request.args.get('origin')
        useadb = request.args.get('adb', False)
        self._logger.info('MADmin: Making screenshot ({})', str(origin))

        devicemappings = self._mapping_manager.get_all_devicemappings()
        adb = devicemappings.get(origin, {}).get('adb', False)
        filename = generate_device_screenshot_path(origin, devicemappings,
                                                   self._args)

        if useadb == 'True' and self._adb_connect.make_screenshot(
                adb, origin, "jpg"):
            self._logger.info('MADMin: ADB screenshot successfully ({})',
                              str(origin))
        else:
            self.generate_screenshot(origin)

        creationdate = datetime.datetime.fromtimestamp(
            creation_date(filename)).strftime(self._datetimeformat)

        return creationdate

    def generate_screenshot(self, origin):
        devicemappings = self._mapping_manager.get_all_devicemappings()
        screenshot_type: ScreenshotType = ScreenshotType.JPEG
        if devicemappings.get(origin, {}).get("screenshot_type",
                                              "jpeg") == "png":
            screenshot_type = ScreenshotType.PNG

        screenshot_quality: int = devicemappings.get(origin, {}).get(
            "screenshot_quality", 80)

        temp_comm = self._ws_server.get_origin_communicator(origin)
        temp_comm.get_screenshot(
            generate_device_screenshot_path(origin, devicemappings,
                                            self._args), screenshot_quality,
            screenshot_type)

        filename = generate_device_screenshot_path(origin, devicemappings,
                                                   self._args)
        image_resize(filename,
                     os.path.join(mapadroid.MAD_ROOT, self._args.temp_path,
                                  "madmin"),
                     width=250)

        return

    @auth_required
    def click_screenshot(self):
        origin = request.args.get('origin')
        click_x = request.args.get('clickx')
        click_y = request.args.get('clicky')
        useadb = request.args.get('adb')
        devicemappings = self._mapping_manager.get_all_devicemappings()

        filename = generate_device_screenshot_path(origin, devicemappings,
                                                   self._args)
        with Image.open(filename) as screenshot:
            width, height = screenshot.size

        real_click_x = int(width / float(click_x))
        real_click_y = int(height / float(click_y))
        adb = devicemappings.get(origin, {}).get('adb', False)

        if useadb == 'True' and self._adb_connect.make_screenclick(
                adb, origin, real_click_x, real_click_y):
            self._logger.info('MADMin: ADB screenclick successfully ({})',
                              str(origin))
        else:
            self._logger.info('MADMin WS Click x:{} y:{} ({})',
                              str(real_click_x), str(real_click_y),
                              str(origin))
            temp_comm = self._ws_server.get_origin_communicator(origin)
            temp_comm.click(int(real_click_x), int(real_click_y))

        time.sleep(2)
        return self.take_screenshot(origin, useadb)

    @auth_required
    def swipe_screenshot(self):
        origin = request.args.get('origin')
        click_x = request.args.get('clickx')
        click_y = request.args.get('clicky')
        click_xe = request.args.get('clickxe')
        click_ye = request.args.get('clickye')
        useadb = request.args.get('adb')

        devicemappings = self._mapping_manager.get_all_devicemappings()

        filename = generate_device_screenshot_path(origin, devicemappings,
                                                   self._args)
        with Image.open(filename) as screenshot:
            width, height = screenshot.size

        real_click_x = int(width / float(click_x))
        real_click_y = int(height / float(click_y))
        real_click_xe = int(width / float(click_xe))
        real_click_ye = int(height / float(click_ye))
        adb = devicemappings.get(origin, {}).get('adb', False)

        if useadb == 'True' and self._adb_connect.make_screenswipe(
                adb, origin, real_click_x, real_click_y, real_click_xe,
                real_click_ye):
            self._logger.info('MADMin: ADB screenswipe successfully ({})',
                              str(origin))
        else:
            self._logger.info('MADMin WS Swipe x:{} y:{} xe:{} ye:{} ({})',
                              str(real_click_x), str(real_click_y),
                              str(real_click_xe), str(real_click_ye),
                              str(origin))
            temp_comm = self._ws_server.get_origin_communicator(origin)
            temp_comm.touch_and_hold(int(real_click_x), int(real_click_y),
                                     int(real_click_xe), int(real_click_ye))

        time.sleep(2)
        return self.take_screenshot(origin, useadb)

    @auth_required
    def quit_pogo(self):
        origin = request.args.get('origin')
        useadb = request.args.get('adb')
        restart = request.args.get('restart')
        devicemappings = self._mapping_manager.get_all_devicemappings()
        adb = devicemappings.get(origin, {}).get('adb', False)
        device_id = devicemappings.get(origin, {}).get('device_id', False)
        if device_id != False:
            self._db.save_last_restart(device_id)
        self._logger.info('MADmin: Restart Pogo ({})', str(origin))
        if useadb == 'True' and \
                self._adb_connect.send_shell_command(adb, origin, "am force-stop com.nianticlabs.pokemongo"):
            self._logger.info(
                'MADMin: ADB shell force-stop game command successfully ({})',
                str(origin))
            if restart:
                time.sleep(1)
                started = self._adb_connect.send_shell_command(
                    adb, origin, "am start com.nianticlabs.pokemongo")
                if started:
                    self._logger.info(
                        'MADMin: ADB shell start game command successfully ({})',
                        str(origin))
                else:
                    self._logger.error(
                        'MADMin: ADB shell start game command failed ({})',
                        str(origin))
        else:
            temp_comm = self._ws_server.get_origin_communicator(origin)
            if restart:
                self._logger.info('MADMin: trying to restart game on {}',
                                  str(origin))
                temp_comm.restart_app("com.nianticlabs.pokemongo")

                time.sleep(1)
            else:
                self._logger.info('MADMin: trying to stop game on {}',
                                  str(origin))
                temp_comm.stop_app("com.nianticlabs.pokemongo")

            self._logger.info('MADMin: WS command successfully ({})',
                              str(origin))
        time.sleep(2)
        return self.take_screenshot(origin, useadb)

    @auth_required
    def restart_phone(self):
        origin = request.args.get('origin')
        useadb = request.args.get('adb')
        devicemappings = self._mapping_manager.get_all_devicemappings()
        adb = devicemappings.get(origin, {}).get('adb', False)
        device_id = devicemappings.get(origin, {}).get('device_id', False)
        if device_id != False:
            self._db.save_last_reboot(device_id)
        self._logger.info('MADmin: Restart device ({})', str(origin))
        if (useadb == 'True' and self._adb_connect.send_shell_command(
                adb, origin,
                "am broadcast -a android.intent.action.BOOT_COMPLETED")):
            self._logger.info('MADMin: ADB shell command successfully ({})',
                              str(origin))
        else:
            temp_comm = self._ws_server.get_origin_communicator(origin)
            temp_comm.reboot()
        self._ws_server.force_disconnect(origin)
        return redirect(url_for('get_phonescreens'), code=302)

    @auth_required
    def clear_game_data(self):
        origin = request.args.get('origin')
        useadb = request.args.get('adb')
        devicemappings = self._mapping_manager.get_all_devicemappings()

        adb = devicemappings.get(origin, {}).get('adb', False)
        self._logger.info('MADmin: Clear game data for device ({})',
                          str(origin))
        if (useadb == 'True' and self._adb_connect.send_shell_command(
                adb, origin, "pm clear com.nianticlabs.pokemongo")):
            self._logger.info('MADMin: ADB shell command successfully ({})',
                              str(origin))
        else:
            temp_comm = self._ws_server.get_origin_communicator(origin)
            temp_comm.reset_app_data("com.nianticlabs.pokemongo")
        return redirect(url_for('get_phonescreens'), code=302)

    @auth_required
    def send_gps(self):
        origin = request.args.get('origin')
        devicemappings = self._mapping_manager.get_all_devicemappings()

        useadb = request.args.get('adb')
        if useadb is None:
            useadb = devicemappings.get(origin, {}).get('adb', False)

        coords = request.args.get('coords').replace(' ', '').split(',')
        sleeptime = request.args.get('sleeptime', "0")
        if len(coords) < 2:
            return 'Wrong Format!'
        self._logger.info('MADmin: Set GPS Coords {}, {} - WS Mode only! ({})',
                          str(coords[0]), str(coords[1]), str(origin))
        try:
            temp_comm = self._ws_server.get_origin_communicator(origin)
            temp_comm.set_location(Location(coords[0], coords[1]), 0)
            if int(sleeptime) > 0:
                self._logger.info("MADmin: Set additional sleeptime: {} ({})",
                                  str(sleeptime), str(origin))
                self._ws_server.set_geofix_sleeptime_worker(origin, sleeptime)
        except Exception as e:
            self._logger.exception(
                'MADmin: Exception occurred while set gps coords: {}.', e)

        time.sleep(2)
        return self.take_screenshot(origin, useadb)

    @auth_required
    def send_text(self):
        origin = request.args.get('origin')
        useadb = request.args.get('adb')
        text = request.args.get('text')
        devicemappings = self._mapping_manager.get_all_devicemappings()

        adb = devicemappings.get(origin, {}).get('adb', False)
        if len(text) == 0:
            return 'Empty text'
        self._logger.info('MADmin: Send text ({})', str(origin))
        if useadb == 'True' and self._adb_connect.send_shell_command(
                adb, origin, 'input text "' + text + '"'):
            self._logger.info('MADMin: Send text successfully ({})',
                              str(origin))
        else:
            temp_comm = self._ws_server.get_origin_communicator(origin)
            temp_comm.enter_text(text)

        time.sleep(2)
        return self.take_screenshot(origin, useadb)

    @auth_required
    def send_command(self):
        origin = request.args.get('origin')
        useadb = request.args.get('adb')
        command = request.args.get('command')
        devicemappings = self._mapping_manager.get_all_devicemappings()

        adb = devicemappings.get(origin, {}).get('adb', False)
        self._logger.info('MADmin: Sending Command ({})', str(origin))
        if command == 'home':
            cmd = "input keyevent 3"
        elif command == 'back':
            cmd = "input keyevent 4"
        if useadb == 'True' and self._adb_connect.send_shell_command(
                adb, origin, cmd):
            self._logger.info('MADMin: ADB shell command successfully ({})',
                              str(origin))
        else:
            temp_comm = self._ws_server.get_origin_communicator(origin)
            if command == 'home':
                temp_comm.home_button()
            elif command == 'back':
                temp_comm.back_button()

        time.sleep(2)
        return self.take_screenshot(origin, useadb)

    @auth_required
    @logger.catch
    def upload(self):
        if request.method == 'POST':
            # check if the post request has the file part
            if 'file' not in request.files:
                flash('No file part')
                return redirect(url_for('upload'), code=302)
            file = request.files['file']
            if file.filename == '':
                flash('No file selected for uploading')
                return redirect(url_for('upload'), code=302)
            if file and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                file.save(os.path.join(self._args.upload_path, filename))
                flash('File uploaded successfully')
                return redirect(url_for('uploaded_files'), code=302)
            else:
                flash('Allowed file type is apk only!')
                return redirect(url_for('upload'), code=302)

        return render_template('upload.html',
                               header="File Upload",
                               title="File Upload")

    @auth_required
    def get_uploaded_files(self):
        return jsonify(
            uploaded_files(self._datetimeformat,
                           self._device_updater.return_commands()))

    @auth_required
    def uploaded_files(self):
        origin = request.args.get('origin', False)
        useadb = request.args.get('adb', False)
        return render_template('uploaded_files.html',
                               responsive=str(
                                   self._args.madmin_noresponsive).lower(),
                               title="Uploaded Files",
                               origin=origin,
                               adb=useadb)

    @auth_required
    def delete_file(self):
        filename = request.args.get('filename')
        if os.path.exists(os.path.join(self._args.upload_path, filename)):
            os.remove(os.path.join(self._args.upload_path, filename))
            flash('File deleted successfully')
        return redirect(url_for('uploaded_files'), code=302)

    @auth_required
    @logger.catch
    def install_file(self):

        jobname = request.args.get('jobname')
        origin = request.args.get('origin')
        useadb = request.args.get('adb', False)
        type_ = request.args.get('type', None)

        devicemappings = self._mapping_manager.get_all_devicemappings()
        adb = devicemappings.get(origin, {}).get('adb', False)

        if os.path.exists(os.path.join(self._args.upload_path, jobname)):
            if useadb == 'True':
                if self._adb_connect.push_file(adb, origin, os.path.join(self._args.upload_path, jobname)) and \
                        self._adb_connect.send_shell_command(
                            adb, origin, "pm install -r /sdcard/Download/" + str(jobname)):
                    flash('File installed successfully')
                else:
                    flash('File could not be installed successfully :(')
            else:
                self._device_updater.preadd_job(origin=origin,
                                                job=jobname,
                                                id_=int(time.time()),
                                                type=type_)
                flash('File successfully queued --> See Job Status')

        elif type_ != jobType.INSTALLATION:
            self._device_updater.preadd_job(origin=origin,
                                            job=jobname,
                                            id_=int(time.time()),
                                            type=type_)
            flash('Job successfully queued --> See Job Status')

        return redirect(url_for('uploaded_files',
                                origin=str(origin),
                                adb=useadb),
                        code=302)

    @auth_required
    def reload_jobs(self):
        logger.info("Reload existing jobs")
        self._device_updater.init_jobs()
        return redirect(url_for('uploaded_files'), code=302)

    @auth_required
    @logger.catch
    def get_install_log(self):
        withautojobs = request.args.get('withautojobs', False)
        return_log = []
        log = self._device_updater.get_log(withautojobs=withautojobs)
        for entry in log:
            if 'jobname' not in entry:
                entry['jobname'] = entry.get('file', 'Unknown Name')
            return_log.append(entry)

        return jsonify(return_log)

    @auth_required
    @logger.catch()
    def delete_log_entry(self):
        id_ = request.args.get('id')
        if self._device_updater.delete_log_id(id_):
            flash('Job deleted successfully')
        else:
            flash('Job could not be deleted successfully')
        return redirect(url_for('install_status'), code=302)

    @auth_required
    @logger.catch
    def install_status(self):
        withautojobs = request.args.get('withautojobs', False)
        return render_template('installation_status.html',
                               responsive=str(
                                   self._args.madmin_noresponsive).lower(),
                               title="Installation Status",
                               withautojobs=withautojobs)

    @auth_required
    @logger.catch()
    def install_file_all_devices(self):
        jobname = request.args.get('jobname', None)
        type_ = request.args.get('type', None)
        if jobname is None or type_ is None:
            flash('No File or Type selected')
            return redirect(url_for('install_status'), code=302)

        devices = self._mapping_manager.get_all_devices()
        for device in devices:
            self._device_updater.preadd_job(origin=device,
                                            job=jobname,
                                            id_=int(time.time()),
                                            type=type_)
            time.sleep(1)

        flash('Job successfully queued')
        return redirect(url_for('install_status'), code=302)

    @auth_required
    @logger.catch()
    def restart_job(self):
        id: int = request.args.get('id', None)
        if id is not None:
            self._device_updater.restart_job(id)
            flash('Job requeued')
            return redirect(url_for('install_status'), code=302)

        flash('unknown id - restart failed')
        return redirect(url_for('install_status'), code=302)

    @auth_required
    @logger.catch()
    def delete_log(self):
        onlysuccess = request.args.get('only_success', False)
        self._device_updater.delete_log(onlysuccess=onlysuccess)
        return redirect(url_for('install_status'), code=302)

    @auth_required
    def get_all_workers(self):
        devices = self._mapping_manager.get_all_devices()
        devicesreturn = []
        for device in devices:
            devicesreturn.append({'worker': device})

        return jsonify(devicesreturn)

    @auth_required
    def job_for_worker(self):
        jobname = request.args.get('jobname', None)
        type_ = request.args.get('type', None)
        devices = request.args.getlist('device[]')
        for device in devices:
            self._device_updater.preadd_job(origin=device,
                                            job=jobname,
                                            id_=int(time.time()),
                                            type=type_)
            time.sleep(1)

        flash('Job successfully queued')
        return redirect(url_for('install_status'), code=302)