mirror of
https://github.com/Syncplay/syncplay
synced 2025-02-17 03:16:55 +00:00
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:
parent
1bbbab245f
commit
2bf3931f59
@ -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"):
|
||||
|
@ -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"]
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user