def _load(self):
        if not os.path.isfile(self._config.get(Setting.DATA_CACHE_FILE_PATH)):
            self._data = {KEY_SNPASHOTS: {}}
        else:
            with open(self._config.get(Setting.DATA_CACHE_FILE_PATH)) as f:
                self._data = json.load(f)

        # Check for an upgrade.
        if KEY_LAST_VERSION in self._data:
            self._last_version = Version.parse(self._data[KEY_LAST_VERSION])
        if self.previousVersion != self.currentVersion:
            # add an upgrade marker
            if KEY_UPGRADES not in self._data:
                self._data[KEY_UPGRADES] = []
            self._data[KEY_UPGRADES].append({
                'prev_version':
                str(self.previousVersion),
                'new_version':
                str(self.currentVersion),
                'date':
                self._time.now().isoformat()
            })
            self._data[KEY_LAST_VERSION] = str(self.currentVersion)
            self.makeDirty()
            self.saveIfDirty()

        if self.previousVersion == Version.default(
        ) and self.currentVersion > Version.parse("0.103"):
            self._flags.add(UpgradeFlags.DONT_IGNORE_LEGACY_SNAPSHOTS)
    async def authorize(self, request: Request):
        if 'redirectbacktoken' in request.query:
            version = Version.parse(request.query.get('version', "0"))
            token_url = request.query.get('redirectbacktoken')
            return_url = request.query.get('return', None)
            state = {
                'v': str(version),
                'token': token_url,
                'return': return_url,
                'bg': self.base_context(request).get('backgroundColor'),
                'ac': self.base_context(request).get('accentColor'),
            }
            # Someone is trying to authenticate with the add-on, direct them to the google auth url
            raise HTTPSeeOther(await self.exchanger.getAuthorizationUrl(
                json.dumps(state)))
        elif 'state' in request.query and 'code' in request.query:
            state = json.loads(unquote(request.query.get('state')))
            code = request.query.get('code')
            try:
                version = Version.parse(state["v"])
                creds = (await self.exchanger.exchange(code)).serialize(
                    include_secret=False)

                if version < NEW_AUTH_MINIMUM:
                    # Redirect back to the addon, since this is the older addon
                    url = URL(state['token']).with_query(
                        {'creds': json.dumps(creds)})
                    raise HTTPSeeOther(url)

                serialized_creds = str(
                    base64.b64encode(json.dumps(creds).encode("utf-8")),
                    "utf-8")
                url = URL(state['token']).with_query({
                    'creds': serialized_creds,
                    'host': state['return']
                })
                context = {
                    **self.base_context(request),
                    'redirect_url': str(url),
                    'credentials_serialized': serialized_creds,
                }
                if 'bg' in state:
                    context['backgroundColor'] = state['bg']
                if 'ac' in state:
                    context['accentColor'] = state['ac']
                return aiohttp_jinja2.render_template("authorize.jinja2",
                                                      request, context)
            except Exception as e:
                if isinstance(e, HTTPSeeOther):
                    # expected, pass this thorugh
                    raise
                self.logError(request, e)
                content = "The server encountered an error while processing this request: " + str(
                    e) + "<br/>"
                content += "Please <a href='https://github.com/sabeechen/hassio-google-drive-backup/issues'>file an issue</a> on Home Assistant Google Backup's GitHub page so I'm aware of this problem or attempt authorizing with Google Drive again."
                return Response(status=500, body=content)
        else:
            raise HTTPBadRequest()
Пример #3
0
    def _load(self):
        if not os.path.isfile(self._config.get(Setting.DATA_CACHE_FILE_PATH)):
            self._data = {NECESSARY_OLD_BACKUP_PLURAL_NAME: {}}
        else:
            with open(self._config.get(Setting.DATA_CACHE_FILE_PATH)) as f:
                self._data = json.load(f)

        # Check for an upgrade.
        if KEY_LAST_VERSION in self._data:
            self._last_version = Version.parse(self._data[KEY_LAST_VERSION])
        if self.previousVersion != self.currentVersion:
            # add an upgrade marker
            if KEY_UPGRADES not in self._data:
                self._data[KEY_UPGRADES] = []
            self._data[KEY_UPGRADES].append({
                'prev_version':
                str(self.previousVersion),
                'new_version':
                str(self.currentVersion),
                'date':
                self._time.now().isoformat()
            })
            self._data[KEY_LAST_VERSION] = str(self.currentVersion)
            self.makeDirty()
            self.saveIfDirty()
 async def picker(self, request: Request):
     version = Version.parse(request.query.get('version', "0"))
     bg = request.query.get('bg', self.config.get(Setting.BACKGROUND_COLOR))
     ac = request.query.get('ac', self.config.get(Setting.ACCENT_COLOR))
     return {
         **self.base_context(request),
         "client_id": self.config.get(Setting.DEFAULT_DRIVE_CLIENT_ID),
         "developer_key": self.config.get(Setting.DRIVE_PICKER_API_KEY),
         "app_id": self.config.get(Setting.DEFAULT_DRIVE_CLIENT_ID).split("-")[0],
         'backgroundColor': bg,
         'accentColor': ac,
         "do_redirect": str(version < NEW_AUTH_MINIMUM).lower()
     }
 def getUpgradeTime(self, version: Version):
     for upgrade in self._data[KEY_UPGRADES]:
         if Version.parse(upgrade['new_version']) >= version:
             return self._time.parse(upgrade['date'])
     return self._time.now()
 def currentVersion(self):
     return Version.parse(VERSION)
async def test_version_upgrades(time: Time, injector: Injector,
                                config: Config) -> None:
    # Simluate upgrading from an un-tracked version
    assert not os.path.exists(config.get(Setting.DATA_CACHE_FILE_PATH))
    cache = injector.get(DataCache)
    upgrade_time = time.now()
    assert cache.previousVersion == Version.default()
    assert cache.currentVersion == Version.parse(VERSION)
    assert cache.checkFlag(UpgradeFlags.DONT_IGNORE_LEGACY_SNAPSHOTS)

    assert os.path.exists(config.get(Setting.DATA_CACHE_FILE_PATH))
    with open(config.get(Setting.DATA_CACHE_FILE_PATH)) as f:
        data = json.load(f)
        assert data["upgrades"] == [{
            "prev_version": str(Version.default()),
            "new_version": VERSION,
            "date": upgrade_time.isoformat()
        }]

    # Reload the data cache, verify there is no upgrade.
    time.advance(days=1)
    cache = DataCache(config, time)
    assert cache.previousVersion == Version.parse(VERSION)
    assert cache.currentVersion == Version.parse(VERSION)
    assert not cache.checkFlag(UpgradeFlags.DONT_IGNORE_LEGACY_SNAPSHOTS)
    assert os.path.exists(config.get(Setting.DATA_CACHE_FILE_PATH))

    with open(config.get(Setting.DATA_CACHE_FILE_PATH)) as f:
        data = json.load(f)
        assert data["upgrades"] == [{
            "prev_version": str(Version.default()),
            "new_version": VERSION,
            "date": upgrade_time.isoformat()
        }]

    # simulate upgrading to a new version, verify an upgrade gets identified.
    upgrade_version = Version.parse("200")

    class UpgradeCache(DataCache):
        def __init__(self):
            super().__init__(config, time)

        @property
        def currentVersion(self):
            return upgrade_version

    cache = UpgradeCache()
    assert cache.previousVersion == Version.parse(VERSION)
    assert cache.currentVersion == upgrade_version
    assert os.path.exists(config.get(Setting.DATA_CACHE_FILE_PATH))

    with open(config.get(Setting.DATA_CACHE_FILE_PATH)) as f:
        data = json.load(f)
        assert data["upgrades"] == [{
            "prev_version": str(Version.default()),
            "new_version": VERSION,
            "date": upgrade_time.isoformat()
        }, {
            "prev_version": VERSION,
            "new_version": str(upgrade_version),
            "date": time.now().isoformat()
        }]

    next_upgrade_time = time.now()
    time.advance(days=1)
    # Verify version upgrade time queries work as expected
    assert cache.getUpgradeTime(Version.parse(VERSION)) == upgrade_time
    assert cache.getUpgradeTime(Version.default()) == upgrade_time
    assert cache.getUpgradeTime(upgrade_version) == next_upgrade_time

    # degenerate case, should never happen but a sensible value needs to be returned
    assert cache.getUpgradeTime(Version.parse("201")) == time.now()
Пример #8
0
def test_broken_versions():
    assert Version.parse("") == Version.default()
    assert Version.parse(".") == Version.default()
    assert Version.parse("empty") == Version.default()
    assert Version.parse("no.version.here") == Version.default()
Пример #9
0
def test_junk_strings():
    assert Version.parse("1-.2.3.1") == Version(1, 2, 3, 1)
    assert Version.parse("ignore-1.2.3.1") == Version(1, 2, 3, 1)
    assert Version.parse(
        "1.2.ignore.this.text.3.and...andhere.too.1") == Version(1, 2, 3, 1)
Пример #10
0
def test_parse_staging():
    assert Version.parse("1.0.staging.1") == Version(1, 0, 1)
    assert Version.parse("1.0.staging.1").staging
    assert Version.parse("1.0.staging.1") > Version(1.0)
    assert Version.parse("1.2.3") == Version(1, 2, 3)
Пример #11
0
def test_parse():
    assert Version.parse("1.0") == Version(1, 0)
    assert Version.parse("1.2.3") == Version(1, 2, 3)