Trusted Domains: Allow trusting a domain regardless of HTTP basic auth credentials (#437)

* Trusted Domains: don't consider HTTP basic auth credentials part of the domain name

* Trusted Domains: hide "add as trusted domain" menu item if entry does not contain domain

* Trusted Domains: strip HTTP basic auth credentials also when adding as trusted domain via context menu
This commit is contained in:
Tremolo4 2021-10-17 14:44:07 +02:00 committed by GitHub
parent 1bbbab245f
commit 2bf3931f59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 25 deletions

View File

@ -9,9 +9,9 @@ import re
import sys
import threading
import time
from fnmatch import fnmatch
from copy import deepcopy
from functools import wraps
from urllib.parse import urlparse
from twisted.application.internet import ClientService
from twisted.internet.endpoints import HostnameEndpoint
@ -546,27 +546,47 @@ class SyncplayClient(object):
if oldRoomList != newRoomList:
self._config['roomList'] = newRoomList
def _isURITrustableAndTrusted(self, URIToTest):
"""Returns a tuple of booleans: (trustable, trusted).
A given URI is "trustable" if it uses HTTP or HTTPS (constants.TRUSTABLE_WEB_PROTOCOLS).
A given URI is "trusted" if it matches an entry in the trustedDomains config.
Such an entry is considered matching if the domain is the same and the path
is a prefix of the given URI's path.
A "trustable" URI is always "trusted" if the config onlySwitchToTrustedDomains is false.
"""
o = urlparse(URIToTest)
trustable = o.scheme in constants.TRUSTABLE_WEB_PROTOCOLS
if not trustable:
# untrustable URIs are never trusted, return early
return False, False
if not self._config['onlySwitchToTrustedDomains']:
# trust all trustable URIs in this case
return trustable, True
# check for matching trusted domains
if self._config['trustedDomains']:
for entry in self._config['trustedDomains']:
trustedDomain, _, path = entry.partition('/')
if o.hostname not in (trustedDomain, "www." + trustedDomain):
# domain does not match
continue
if path and not o.path.startswith('/' + path):
# trusted domain has a path component and it does not match
continue
# match found, trust this domain
return trustable, True
# no matches found, do not trust this domain
return trustable, False
def isUntrustedTrustableURI(self, URIToTest):
if utils.isURL(URIToTest):
for trustedProtocol in constants.TRUSTABLE_WEB_PROTOCOLS:
if URIToTest.startswith(trustedProtocol) and not self.isURITrusted(URIToTest):
return True
trustable, trusted = self._isURITrustableAndTrusted(URIToTest)
return trustable and not trusted
return False
def isURITrusted(self, URIToTest):
URIToTest = URIToTest+"/"
for trustedProtocol in constants.TRUSTABLE_WEB_PROTOCOLS:
if URIToTest.startswith(trustedProtocol):
if self._config['onlySwitchToTrustedDomains']:
if self._config['trustedDomains']:
for trustedDomain in self._config['trustedDomains']:
trustableURI = ''.join([trustedProtocol, trustedDomain, "/*"])
if fnmatch(URIToTest, trustableURI):
return True
return False
else:
return True
return False
trustable, trusted = self._isURITrustableAndTrusted(URIToTest)
return trustable and trusted
def openFile(self, filePath, resetPosition=False, fromUser=False):
if fromUser and filePath.endswith(".txt") or filePath.endswith(".m3u") or filePath.endswith(".m3u8"):

View File

@ -345,6 +345,6 @@ SYNCPLAY_DOWNLOAD_URL = "https://syncplay.pl/download/"
SYNCPLAY_PUBLIC_SERVER_LIST_URL = "https://syncplay.pl/listpublicservers?{}" # Params
DEFAULT_TRUSTED_DOMAINS = ["youtube.com", "youtu.be"]
TRUSTABLE_WEB_PROTOCOLS = ["http://www.", "https://www.", "http://", "https://"]
TRUSTABLE_WEB_PROTOCOLS = ["http", "https"]
PRIVATE_FILE_FIELDS = ["path"]

View File

@ -731,7 +731,8 @@ class MainWindow(QtWidgets.QMainWindow):
lambda: utils.open_system_file_browser(pathFound))
if self._syncplayClient.isUntrustedTrustableURI(firstFile):
domain = utils.getDomainFromURL(firstFile)
menu.addAction(QtGui.QPixmap(resourcespath + "shield_add.png"), getMessage("addtrusteddomain-menu-label").format(domain), lambda: self.addTrustedDomain(domain))
if domain:
menu.addAction(QtGui.QPixmap(resourcespath + "shield_add.png"), getMessage("addtrusteddomain-menu-label").format(domain), lambda: self.addTrustedDomain(domain))
menu.addAction(QtGui.QPixmap(resourcespath + "delete.png"), getMessage("removefromplaylist-menu-label"), lambda: self.deleteSelectedPlaylistItems())
menu.addSeparator()
menu.addAction(QtGui.QPixmap(resourcespath + "arrow_switch.png"), getMessage("shuffleremainingplaylist-menu-label"), lambda: self.shuffleRemainingPlaylist())
@ -794,7 +795,8 @@ class MainWindow(QtWidgets.QMainWindow):
menu.addAction(QtGui.QPixmap(resourcespath + "film_go.png"), getMessage("openusersfile-menu-label").format(shortUsername), lambda: self.openFile(pathFound, resetPosition=False, fromUser=True))
if self._syncplayClient.isUntrustedTrustableURI(filename):
domain = utils.getDomainFromURL(filename)
menu.addAction(QtGui.QPixmap(resourcespath + "shield_add.png"), getMessage("addtrusteddomain-menu-label").format(domain), lambda: self.addTrustedDomain(domain))
if domain:
menu.addAction(QtGui.QPixmap(resourcespath + "shield_add.png"), getMessage("addtrusteddomain-menu-label").format(domain), lambda: self.addTrustedDomain(domain))
if not isURL(filename) and filename != getMessage("nofile-note"):
path = self._syncplayClient.fileSwitch.findFilepath(filename)

View File

@ -395,12 +395,15 @@ def playlistIsValid(files):
def getDomainFromURL(URL):
try:
URL = URL.split("//")[-1].split("/")[0]
if URL.startswith("www."):
URL = URL[4:]
return URL
except:
o = urllib.parse.urlparse(URL)
except ValueError:
# not a URL
return None
if o.hostname is not None and o.hostname.startswith("www."):
return o.hostname[4:]
else:
# may return None if URL does not have domain (invalid url)
return o.hostname
def open_system_file_browser(path):