def exchange_authorization_code(self, authorization_code, scopes, callback): log.debug( "OAuth: exchanging authorization_code %s for an access_token", authorization_code) path = "/oauth2/token" url = QUrl() url_query = QUrlQuery() url_query.addQueryItem("grant_type", "authorization_code") url_query.addQueryItem("code", authorization_code) url_query.addQueryItem("client_id", MUSICBRAINZ_OAUTH_CLIENT_ID) url_query.addQueryItem("client_secret", MUSICBRAINZ_OAUTH_CLIENT_SECRET) url_query.addQueryItem("redirect_uri", "urn:ietf:wg:oauth:2.0:oob") url.setQuery(url_query.query(QUrl.FullyEncoded)) data = url.query() self.webservice.post( self.host, self.port, path, data, partial(self.on_exchange_authorization_code_finished, scopes, callback), mblogin=True, priority=True, important=True, request_mimetype="application/x-www-form-urlencoded")
def exchange_authorization_code(self, authorization_code, scopes, callback): log.debug( "OAuth: exchanging authorization_code %s for an access_token", authorization_code) host, port = config.setting['server_host'], config.setting[ 'server_port'] path = "/oauth2/token" url = QUrl() url_query = QUrlQuery() url_query.addQueryItem("grant_type", "authorization_code") url_query.addQueryItem("code", authorization_code) url_query.addQueryItem("client_id", MUSICBRAINZ_OAUTH_CLIENT_ID) url_query.addQueryItem("client_secret", MUSICBRAINZ_OAUTH_CLIENT_SECRET) url_query.addQueryItem("redirect_uri", "urn:ietf:wg:oauth:2.0:oob") url.setQuery(url_query.query(QUrl.FullyEncoded)) data = string_(url.query()) self.xmlws.post(host, port, path, data, partial(self.on_exchange_authorization_code_finished, scopes, callback), xml=False, mblogin=True, priority=True, important=True)
def refresh_access_token(self, callback): refresh_token = config.persist["oauth_refresh_token"] log.debug("OAuth: refreshing access_token with a refresh_token %s", refresh_token) host, port = config.setting['server_host'], config.setting[ 'server_port'] path = "/oauth2/token" url = QUrl() url_query = QUrlQuery() url_query.addQueryItem("grant_type", "refresh_token") url_query.addQueryItem("refresh_token", refresh_token) url_query.addQueryItem("client_id", MUSICBRAINZ_OAUTH_CLIENT_ID) url_query.addQueryItem("client_secret", MUSICBRAINZ_OAUTH_CLIENT_SECRET) url.setQuery(url_query.query(QUrl.FullyEncoded)) data = string_(url.query()) self.xmlws.post(host, port, path, data, partial(self.on_refresh_access_token_finished, callback), xml=False, mblogin=True, priority=True, important=True)
def query_string(qurl: QUrl) -> str: """Get a query string for the given URL. This is a WORKAROUND for: https://www.riverbankcomputing.com/pipermail/pyqt/2017-November/039702.html """ try: return qurl.query() except AttributeError: # pragma: no cover return QUrlQuery(qurl).query()
def data_for_url(url: QUrl) -> Tuple[str, bytes]: """Get the data to show for the given URL. Args: url: The QUrl to show. Return: A (mimetype, data) tuple. """ norm_url = url.adjusted( QUrl.NormalizePathSegments | # type: ignore[arg-type] QUrl.StripTrailingSlash) if norm_url != url: raise Redirect(norm_url) path = url.path() host = url.host() query = url.query() # A url like "qute:foo" is split as "scheme:path", not "scheme:host". log.misc.debug("url: {}, path: {}, host {}".format( url.toDisplayString(), path, host)) if not path or not host: new_url = QUrl() new_url.setScheme('qute') # When path is absent, e.g. qute://help (with no trailing slash) if host: new_url.setHost(host) # When host is absent, e.g. qute:help else: new_url.setHost(path) new_url.setPath('/') if query: new_url.setQuery(query) if new_url.host(): # path was a valid host raise Redirect(new_url) try: handler = _HANDLERS[host] except KeyError: raise NotFoundError("No handler found for {}".format( url.toDisplayString())) try: mimetype, data = handler(url) except OSError as e: raise SchemeOSError(e) assert mimetype is not None, url if mimetype == 'text/html' and isinstance(data, str): # We let handlers return HTML as text data = data.encode('utf-8', errors='xmlcharrefreplace') assert isinstance(data, bytes) return mimetype, data
def refresh_access_token(self, callback): refresh_token = config.persist["oauth_refresh_token"] log.debug("OAuth: refreshing access_token with a refresh_token %s", refresh_token) host, port = config.setting['server_host'], config.setting['server_port'] path = "/oauth2/token" url = QUrl() url_query = QUrlQuery() url_query.addQueryItem("grant_type", "refresh_token") url_query.addQueryItem("refresh_token", refresh_token) url_query.addQueryItem("client_id", MUSICBRAINZ_OAUTH_CLIENT_ID) url_query.addQueryItem("client_secret", MUSICBRAINZ_OAUTH_CLIENT_SECRET) url.setQuery(url_query.query(QUrl.FullyEncoded)) data = string_(url.query()) self.webservice.post(host, port, path, data, partial(self.on_refresh_access_token_finished, callback), parse_response_type=None, mblogin=True, priority=True, important=True)
def exchange_authorization_code(self, authorization_code, scopes, callback): log.debug("OAuth: exchanging authorization_code %s for an access_token", authorization_code) host, port = config.setting['server_host'], config.setting['server_port'] path = "/oauth2/token" url = QUrl() url_query = QUrlQuery() url_query.addQueryItem("grant_type", "authorization_code") url_query.addQueryItem("code", authorization_code) url_query.addQueryItem("client_id", MUSICBRAINZ_OAUTH_CLIENT_ID) url_query.addQueryItem("client_secret", MUSICBRAINZ_OAUTH_CLIENT_SECRET) url_query.addQueryItem("redirect_uri", "urn:ietf:wg:oauth:2.0:oob") url.setQuery(url_query.query(QUrl.FullyEncoded)) data = string_(url.query()) self.webservice.post(host, port, path, data, partial(self.on_exchange_authorization_code_finished, scopes, callback), parse_response_type=None, mblogin=True, priority=True, important=True)
def requestPixmap(self, id, size): url = QUrl(id) query = QUrlQuery(url.query()) map_dir = QDir(url.toLocalFile()).path() dot_size = round(float(query.queryItemValue('dot_size'))) should_flip = query.queryItemValue('flip') in ['True', 'true'] opacity = round(float(query.queryItemValue('opacity'))) try: img, size = self._generate_heatmap(map_dir, dot_size, opacity) if should_flip: img = flip(img) p = QPixmap.fromImage(img.toqimage()) return p, size except Exception: return QPixmap(), QSize(-1, -1)
def refresh_access_token(self, callback): log.debug("OAuth: refreshing access_token with a refresh_token %s", self.refresh_token) path = "/oauth2/token" url = QUrl() url_query = QUrlQuery() url_query.addQueryItem("grant_type", "refresh_token") url_query.addQueryItem("refresh_token", self.refresh_token) url_query.addQueryItem("client_id", MUSICBRAINZ_OAUTH_CLIENT_ID) url_query.addQueryItem("client_secret", MUSICBRAINZ_OAUTH_CLIENT_SECRET) url.setQuery(url_query.query(QUrl.FullyEncoded)) data = url.query() self.webservice.post( self.host, self.port, path, data, partial(self.on_refresh_access_token_finished, callback), mblogin=True, priority=True, important=True, request_mimetype="application/x-www-form-urlencoded")
def parse_javascript_url(url: QUrl) -> str: """Get JavaScript source from the given URL. See https://wiki.whatwg.org/wiki/URL_schemes#javascript:_URLs and https://github.com/whatwg/url/issues/385 """ ensure_valid(url) if url.scheme() != 'javascript': raise Error("Expected a javascript:... URL") if url.authority(): raise Error("URL contains unexpected components: {}".format( url.authority())) code = url.path(QUrl.FullyDecoded) if url.hasQuery(): code += '?' + url.query(QUrl.FullyDecoded) if url.hasFragment(): code += '#' + url.fragment(QUrl.FullyDecoded) if not code: raise Error("Resulted in empty JavaScript code") return code
class CoverArtImage: # Indicate if types are provided by the source, ie. CAA or certain file # formats may have types associated with cover art, but some other sources # don't provide such information support_types = False # `is_front` has to be explicitly set, it is used to handle CAA is_front # indicator is_front = None sourceprefix = "URL" def __init__(self, url=None, types=None, comment='', data=None): if types is None: self.types = [] else: self.types = types if url is not None: self.parse_url(url) else: self.url = None self.comment = comment self.datahash = None # thumbnail is used to link to another CoverArtImage, ie. for PDFs self.thumbnail = None self.can_be_saved_to_tags = True self.can_be_saved_to_disk = True self.can_be_saved_to_metadata = True if data is not None: self.set_data(data) def parse_url(self, url): self.url = QUrl(url) self.host = string_(self.url.host()) self.port = self.url.port(80) self.path = string_(self.url.path(QUrl.FullyEncoded)) if self.url.hasQuery(): self.path += '?' + string_(self.url.query(QUrl.FullyEncoded)) @property def source(self): if self.url is not None: return "%s: %s" % (self.sourceprefix, self.url.toString()) else: return "%s" % self.sourceprefix def is_front_image(self): """Indicates if image is considered as a 'front' image. It depends on few things: - if `is_front` was set, it is used over anything else - if `types` was set, search for 'front' in it - if `support_types` is False, default to True for any image - if `support_types` is True, default to False for any image """ if not self.can_be_saved_to_metadata: # ignore thumbnails return False if self.is_front is not None: return self.is_front if 'front' in self.types: return True return (self.support_types is False) def imageinfo_as_string(self): if self.datahash is None: return "" return "w=%d h=%d mime=%s ext=%s datalen=%d file=%s" % (self.width, self.height, self.mimetype, self.extension, self.datalength, self.tempfile_filename) def __repr__(self): p = [] if self.url is not None: p.append("url=%r" % self.url.toString()) if self.types: p.append("types=%r" % self.types) if self.is_front is not None: p.append("is_front=%r" % self.is_front) if self.comment: p.append("comment=%r" % self.comment) return "%s(%s)" % (self.__class__.__name__, ", ".join(p)) def __str__(self): p = ['Image'] if self.url is not None: p.append("from %s" % self.url.toString()) if self.types: p.append("of type %s" % ','.join(self.types)) if self.comment: p.append("and comment '%s'" % self.comment) return ' '.join(p) def __eq__(self, other): if self and other: if self.types and other.types: return (self.datahash, self.types) == (other.datahash, other.types) else: return self.datahash == other.datahash elif not self and not other: return True else: return False def __hash__(self): if self.datahash is None: return 0 return hash(self.datahash.hash()) def set_data(self, data): """Store image data in a file, if data already exists in such file it will be re-used and no file write occurs """ if self.datahash: self.datahash.delete_file() self.datahash = None try: (self.width, self.height, self.mimetype, self.extension, self.datalength) = imageinfo.identify(data) except imageinfo.IdentificationError as e: raise CoverArtImageIdentificationError(e) try: self.datahash = DataHash(data, suffix=self.extension) except (OSError, IOError) as e: raise CoverArtImageIOError(e) @property def maintype(self): """Returns one type only, even for images having more than one type set. This is mostly used when saving cover art to tags because most formats don't support multiple types for one image. Images coming from CAA can have multiple types (ie. 'front, booklet'). """ if self.is_front_image() or not self.types or 'front' in self.types: return 'front' # TODO: do something better than randomly using the first in the list return self.types[0] def _make_image_filename(self, filename, dirname, metadata): filename = ScriptParser().eval(filename, metadata) if config.setting["ascii_filenames"]: if isinstance(filename, str): filename = unaccent(filename) filename = replace_non_ascii(filename) if not filename: filename = "cover" if not os.path.isabs(filename): filename = os.path.join(dirname, filename) # replace incompatible characters if config.setting["windows_compatibility"] or sys.platform == "win32": filename = replace_win32_incompat(filename) # remove null characters if isinstance(filename, bytes): filename = filename.replace(b"\x00", "") return encode_filename(filename) def save(self, dirname, metadata, counters): """Saves this image. :dirname: The name of the directory that contains the audio file :metadata: A metadata object :counters: A dictionary mapping filenames to the amount of how many images with that filename were already saved in `dirname`. """ if not self.can_be_saved_to_disk: return if (config.setting["caa_image_type_as_filename"] and not self.is_front_image()): filename = self.maintype log.debug("Make cover filename from types: %r -> %r", self.types, filename) else: filename = config.setting["cover_image_filename"] log.debug("Using default cover image filename %r", filename) filename = self._make_image_filename(filename, dirname, metadata) overwrite = config.setting["save_images_overwrite"] ext = encode_filename(self.extension) image_filename = self._next_filename(filename, counters) while os.path.exists(image_filename + ext) and not overwrite: if not self._is_write_needed(image_filename + ext): break image_filename = self._next_filename(filename, counters) else: new_filename = image_filename + ext # Even if overwrite is enabled we don't need to write the same # image multiple times if not self._is_write_needed(new_filename): return log.debug("Saving cover image to %r", new_filename) try: new_dirname = os.path.dirname(new_filename) if not os.path.isdir(new_dirname): os.makedirs(new_dirname) shutil.copyfile(self.tempfile_filename, new_filename) except (OSError, IOError) as e: raise CoverArtImageIOError(e) def _next_filename(self, filename, counters): if counters[filename]: new_filename = b"%b (%d)" % (filename, counters[filename]) else: new_filename = filename counters[filename] += 1 return new_filename def _is_write_needed(self, filename): if (os.path.exists(filename) and os.path.getsize(filename) == self.datalength): log.debug("Identical file size, not saving %r", filename) return False return True @property def data(self): """Reads the data from the temporary file created for this image. May raise CoverArtImageIOError """ try: return self.datahash.data except (OSError, IOError) as e: raise CoverArtImageIOError(e) @property def tempfile_filename(self): return self.datahash.filename def types_as_string(self, translate=True, separator=', '): if self.types: types = self.types elif self.is_front_image(): types = ['front'] else: types = ['-'] if translate: types = [translate_caa_type(type) for type in types] return separator.join(types)
class CoverArtImage: # Indicate if types are provided by the source, ie. CAA or certain file # formats may have types associated with cover art, but some other sources # don't provide such information support_types = False # Indicates that the source supports multiple types per image. support_multi_types = False # `is_front` has to be explicitly set, it is used to handle CAA is_front # indicator is_front = None sourceprefix = "URL" def __init__(self, url=None, types=None, comment='', data=None, support_types=None, support_multi_types=None): if types is None: self.types = [] else: self.types = types if url is not None: self.parse_url(url) else: self.url = None self.comment = comment self.datahash = None # thumbnail is used to link to another CoverArtImage, ie. for PDFs self.thumbnail = None self.can_be_saved_to_tags = True self.can_be_saved_to_disk = True self.can_be_saved_to_metadata = True if support_types is not None: self.support_types = support_types if support_multi_types is not None: self.support_multi_types = support_multi_types if data is not None: self.set_data(data) def parse_url(self, url): self.url = QUrl(url) self.host = self.url.host() self.port = self.url.port(443 if self.url.scheme() == 'https' else 80) self.path = self.url.path(QUrl.FullyEncoded) if self.url.hasQuery(): self.path += '?' + self.url.query(QUrl.FullyEncoded) @property def source(self): if self.url is not None: return "%s: %s" % (self.sourceprefix, self.url.toString()) else: return "%s" % self.sourceprefix def is_front_image(self): """Indicates if image is considered as a 'front' image. It depends on few things: - if `is_front` was set, it is used over anything else - if `types` was set, search for 'front' in it - if `support_types` is False, default to True for any image - if `support_types` is True, default to False for any image """ if not self.can_be_saved_to_metadata: # ignore thumbnails return False if self.is_front is not None: return self.is_front if 'front' in self.types: return True return (self.support_types is False) def imageinfo_as_string(self): if self.datahash is None: return "" return "w=%d h=%d mime=%s ext=%s datalen=%d file=%s" % ( self.width, self.height, self.mimetype, self.extension, self.datalength, self.tempfile_filename) def __repr__(self): p = [] if self.url is not None: p.append("url=%r" % self.url.toString()) if self.types: p.append("types=%r" % self.types) p.append('support_types=%r' % self.support_types) p.append('support_multi_types=%r' % self.support_types) if self.is_front is not None: p.append("is_front=%r" % self.is_front) if self.comment: p.append("comment=%r" % self.comment) return "%s(%s)" % (self.__class__.__name__, ", ".join(p)) def __str__(self): p = ['Image'] if self.url is not None: p.append("from %s" % self.url.toString()) if self.types: p.append("of type %s" % ','.join(self.types)) if self.comment: p.append("and comment '%s'" % self.comment) return ' '.join(p) def __eq__(self, other): if self and other: if self.support_types and other.support_types: if self.support_multi_types and other.support_multi_types: return (self.datahash, self.types) == (other.datahash, other.types) else: return (self.datahash, self.maintype) == (other.datahash, other.maintype) else: return self.datahash == other.datahash elif not self and not other: return True else: return False def __hash__(self): if self.datahash is None: return 0 return hash(self.datahash.hash()) def set_data(self, data): """Store image data in a file, if data already exists in such file it will be re-used and no file write occurs """ if self.datahash: self.datahash.delete_file() self.datahash = None try: (self.width, self.height, self.mimetype, self.extension, self.datalength) = imageinfo.identify(data) except imageinfo.IdentificationError as e: raise CoverArtImageIdentificationError(e) try: self.datahash = DataHash(data, suffix=self.extension) except (OSError, IOError) as e: raise CoverArtImageIOError(e) @property def maintype(self): """Returns one type only, even for images having more than one type set. This is mostly used when saving cover art to tags because most formats don't support multiple types for one image. Images coming from CAA can have multiple types (ie. 'front, booklet'). """ if self.is_front_image() or not self.types or 'front' in self.types: return 'front' # TODO: do something better than randomly using the first in the list return self.types[0] def _make_image_filename(self, filename, dirname, _metadata): metadata = Metadata() metadata.copy(_metadata) metadata["coverart_maintype"] = self.maintype metadata["coverart_comment"] = self.comment if self.is_front: metadata.add_unique("coverart_types", "front") for cover_type in self.types: metadata.add_unique("coverart_types", cover_type) filename = script_to_filename(filename, metadata) if not filename: filename = "cover" if not os.path.isabs(filename): filename = os.path.join(dirname, filename) return encode_filename(filename) def save(self, dirname, metadata, counters): """Saves this image. :dirname: The name of the directory that contains the audio file :metadata: A metadata object :counters: A dictionary mapping filenames to the amount of how many images with that filename were already saved in `dirname`. """ if not self.can_be_saved_to_disk: return if (config.setting["caa_image_type_as_filename"] and not self.is_front_image()): filename = self.maintype log.debug("Make cover filename from types: %r -> %r", self.types, filename) else: filename = config.setting["cover_image_filename"] log.debug("Using default cover image filename %r", filename) filename = self._make_image_filename(filename, dirname, metadata) overwrite = config.setting["save_images_overwrite"] ext = encode_filename(self.extension) image_filename = self._next_filename(filename, counters) while os.path.exists(image_filename + ext) and not overwrite: if not self._is_write_needed(image_filename + ext): break image_filename = self._next_filename(filename, counters) else: new_filename = image_filename + ext # Even if overwrite is enabled we don't need to write the same # image multiple times if not self._is_write_needed(new_filename): return log.debug("Saving cover image to %r", new_filename) try: new_dirname = os.path.dirname(new_filename) if not os.path.isdir(new_dirname): os.makedirs(new_dirname) shutil.copyfile(self.tempfile_filename, new_filename) except (OSError, IOError) as e: raise CoverArtImageIOError(e) def _next_filename(self, filename, counters): if counters[filename]: new_filename = "%s (%d)" % (decode_filename(filename), counters[filename]) else: new_filename = filename counters[filename] += 1 return encode_filename(new_filename) def _is_write_needed(self, filename): if (os.path.exists(filename) and os.path.getsize(filename) == self.datalength): log.debug("Identical file size, not saving %r", filename) return False return True @property def data(self): """Reads the data from the temporary file created for this image. May raise CoverArtImageIOError """ try: return self.datahash.data except (OSError, IOError) as e: raise CoverArtImageIOError(e) @property def tempfile_filename(self): return self.datahash.filename def normalized_types(self): if self.types: types = sorted(set(self.types)) elif self.is_front_image(): types = ['front'] else: types = ['-'] return types def types_as_string(self, translate=True, separator=', '): types = self.normalized_types() if translate: types = [translate_caa_type(type) for type in types] return separator.join(types)
def _open_wfs(self, name, capabilites_url): # Add new HTTPConnection like in source # https://github.com/qgis/QGIS/blob/master/src/gui/qgsnewhttpconnection.cpp # https://github.com/qgis/QGIS/blob/79616fd8d8285b4eb93adafdfcb97a3e429b832e/src/app/qgisapp.cpp#L3783 self.msg_log_debug(u'add WFS: Name={0}, original URL={1}'.format( name, capabilites_url)) # remove additional url parameters, otherwise adding wfs works the frist time only # https://github.com/qgis/QGIS/blob/9eee12111567a84f4d4de7e020392b3c01c28598/src/gui/qgsnewhttpconnection.cpp#L199-L214 url = QUrl(capabilites_url) query_string = url.query() if query_string: query_string = QUrlQuery(query_string) query_string.removeQueryItem('SERVICE') query_string.removeQueryItem('REQUEST') query_string.removeQueryItem('FORMAT') query_string.removeQueryItem('service') query_string.removeQueryItem('request') query_string.removeQueryItem('format') #also remove VERSION: shouldn't be necessary, but QGIS sometimes seems to append version=1.0.0 query_string.removeQueryItem('VERSION') query_string.removeQueryItem('version') url.setQuery(query_string) capabilites_url = url.toString() self.msg_log_debug(u'add WFS: Name={0}, base URL={1}'.format( name, capabilites_url)) s = QSettings() self.msg_log_debug(u'existing WFS url: {0}'.format( s.value(u'qgis/connections-wfs/{0}/url'.format(name), ''))) key_user = u'qgis/WFS/{0}/username'.format(name) key_pwd = u'qgis/WFS/{0}/password'.format(name) key_referer = u'qgis/connections-wfs/{0}/referer'.format(name) key_url = u'qgis/connections-wfs/{0}/url'.format(name) key_authcfg = u'qgis/WFS/{0}/authcfg'.format(name) s.remove(key_user) s.remove(key_pwd) s.remove(key_referer) s.remove(key_url) s.sync() s.setValue(key_user, '') s.setValue(key_pwd, '') s.setValue(key_referer, '') s.setValue(key_url, capabilites_url) if self.settings.auth_propagate and self.settings.authcfg: s.setValue(key_authcfg, self.settings.authcfg) s.setValue(u'qgis/connections-wfs/selected', name) # create new dialog wfs_dlg = QgsProviderRegistry.instance().selectWidget( "WFS", self.main_win) wfs_dlg = QgsProviderRegistry.instance().createSelectionWidget( "WFS", self.main_win) wfs_dlg.addVectorLayer.connect( lambda url: iface.addVectorLayer(url, name, "WFS")) wfs_dlg.show()
def url_watcher(self, url: QtCore.QUrl): """Watches the QWebEngineView for url changes.""" if url.host() not in [ 'twitch.tv', 'localhost', self.ENDPOINT.host(), 'passport.twitch.tv' ] and url.host() != '': self.LOGGER.warning( f'Redirected to an unsupported host! ({url.host()})') self.LOGGER.debug('Creating informative dialog...') _m = QtWidgets.QMessageBox( QtWidgets.QMessageBox.Critical, 'Token Generator', f'You were redirected to an unsupported host. ({url.host()})', QtWidgets.QMessageBox.Ok, self) self.LOGGER.debug('Displaying dialog...') self.hide() _m.exec() self.LOGGER.debug('Ensuring dialog is deleted properly...') if not sip.isdeleted(_m): _m.deleteLater() self.browser.setUrl(QtCore.QUrl('about:blank')) return self.reject() if url.hasFragment(): query = QtCore.QUrlQuery(url.fragment()) else: query = QtCore.QUrlQuery(url.query()) if not query.hasQueryItem('state') and url.path() != '/two_factor/new': self.LOGGER.warning('No state sent!') self.LOGGER.debug('Creating informative dialog...') _m = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Critical, 'Token Generator', "The state parameter wasn't passed.", QtWidgets.QMessageBox.Ok, self) self.LOGGER.debug('Displaying dialog...') self.hide() _m.exec() self.LOGGER.debug('Ensuring dialog is deleted properly...') if not sip.isdeleted(_m): _m.deleteLater() self.browser.setUrl(QtCore.QUrl('about:blank')) return self.reject() if query.hasQueryItem( 'state') and self._state != query.queryItemValue('state'): self.LOGGER.warning('Sent state is not our state!') self.LOGGER.debug('Creating informative dialog...') _m = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Critical, 'Token Generator', 'Sent state is not our state.', QtWidgets.QMessageBox.Ok, self) self.LOGGER.debug('Displaying dialog...') _m.exec() self.hide() self.LOGGER.debug('Ensuring dialog is deleted properly...') if not sip.isdeleted(_m): _m.deleteLater() self.browser.setUrl(QtCore.QUrl('about:blank')) return self.reject() if query.hasQueryItem('access_token'): # Declarations app: QtWidgets.QApplication = QtWidgets.QApplication.instance() client_id = app.client.settings['extensions']['twitch'][ 'client_id'].value scopes: typing.List[Scopes] = [ Scopes(s) for s in parse.unquote(query.queryItemValue( 'scope')).split('+') ] self.GENERATED.emit( token.Token(client_id, query.queryItemValue('access_token'), scopes)) self.accept()