From bde9aade1173a8a466e3d54e2adc39bea49efe97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Wed, 28 Aug 2024 15:39:03 +0200 Subject: [PATCH 1/7] fixed some potential crashes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Toni Förster --- Model/Store.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Model/Store.swift b/Model/Store.swift index 67e0eee8..3f27eadc 100644 --- a/Model/Store.swift +++ b/Model/Store.swift @@ -20,10 +20,16 @@ final class Store: ResourceObserver, ObservableObject { } func replace(_ items: Data) { - all = items + // Ensure the change happens on the main thread + DispatchQueue.main.async { + self.all = items + } } func clear() { - all = nil + // Ensure clearing happens on the main thread + DispatchQueue.main.async { + self.all = nil + } } } From ed3d9a7d7c42b019137dada1ccdb544597ebd01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Wed, 28 Aug 2024 15:42:35 +0200 Subject: [PATCH 2/7] invidious support for basic auth urls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds user, password and port to the proxy and thumbnail url, if they exist. fixes #614 & #731 Signed-off-by: Toni Förster --- Model/Applications/InvidiousAPI.swift | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Model/Applications/InvidiousAPI.swift b/Model/Applications/InvidiousAPI.swift index c3c1084e..7f685d15 100644 --- a/Model/Applications/InvidiousAPI.swift +++ b/Model/Applications/InvidiousAPI.swift @@ -445,6 +445,9 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI { urlComponents.scheme = instanceURLComponents.scheme urlComponents.host = instanceURLComponents.host + urlComponents.user = instanceURLComponents.user + urlComponents.password = instanceURLComponents.password + urlComponents.port = instanceURLComponents.port guard let url = urlComponents.url else { return nil @@ -563,13 +566,20 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI { return nil } - // some of instances are not configured properly and return thumbnails links - // with incorrect scheme + // Some instances are not configured properly and return thumbnail links + // with an incorrect scheme or a missing port. components.scheme = accountUrlComponents.scheme + components.port = accountUrlComponents.port + + // If basic HTTP authentication is used, + // the username and password need to be prepended to the URL. + components.user = accountUrlComponents.user + components.password = accountUrlComponents.password guard let thumbnailUrl = components.url else { return nil } + print("Final thumbnail URL: \(thumbnailUrl)") return Thumbnail(url: thumbnailUrl, quality: .init(rawValue: quality)!) } From 772e5016c405c9691a82a68c31746539df39f19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Wed, 28 Aug 2024 15:43:15 +0200 Subject: [PATCH 3/7] make sure no log entries are lost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Toni Förster --- .../xcshareddata/xcschemes/Yattee (iOS).xcscheme | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Yattee.xcodeproj/xcshareddata/xcschemes/Yattee (iOS).xcscheme b/Yattee.xcodeproj/xcshareddata/xcschemes/Yattee (iOS).xcscheme index dccf93ab..f526290d 100644 --- a/Yattee.xcodeproj/xcshareddata/xcschemes/Yattee (iOS).xcscheme +++ b/Yattee.xcodeproj/xcshareddata/xcschemes/Yattee (iOS).xcscheme @@ -66,6 +66,11 @@ value = "Yes" isEnabled = "YES"> + + Date: Wed, 28 Aug 2024 16:21:49 +0200 Subject: [PATCH 4/7] sanitise user and password in url MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Toni Förster --- Model/Accounts/AccountsBridge.swift | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Model/Accounts/AccountsBridge.swift b/Model/Accounts/AccountsBridge.swift index 70fe94e3..8997dade 100644 --- a/Model/Accounts/AccountsBridge.swift +++ b/Model/Accounts/AccountsBridge.swift @@ -10,11 +10,28 @@ struct AccountsBridge: Defaults.Bridge { return nil } + // Parse the urlString to check for embedded username and password + var sanitizedUrlString = value.urlString + if var urlComponents = URLComponents(string: value.urlString) { + if let user = urlComponents.user, let password = urlComponents.password { + // Sanitize the embedded username and password + let sanitizedUser = user.addingPercentEncoding(withAllowedCharacters: .urlUserAllowed) ?? user + let sanitizedPassword = password.addingPercentEncoding(withAllowedCharacters: .urlPasswordAllowed) ?? password + + // Update the URL components with sanitized credentials + urlComponents.user = sanitizedUser + urlComponents.password = sanitizedPassword + + // Reconstruct the sanitized URL + sanitizedUrlString = urlComponents.string ?? value.urlString + } + } + return [ "id": value.id, "instanceID": value.instanceID ?? "", "name": value.name, - "apiURL": value.urlString, + "apiURL": sanitizedUrlString, "username": value.username, "password": value.password ?? "" ] From 049a42f2e855b3bcdb2b86910ef3fe929a563e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Wed, 28 Aug 2024 17:40:16 +0200 Subject: [PATCH 5/7] allow basic auth with auth endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Toni Förster --- Model/Applications/InvidiousAPI.swift | 40 +++++++++++++++++++++------ 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/Model/Applications/InvidiousAPI.swift b/Model/Applications/InvidiousAPI.swift index 7f685d15..edb854a9 100644 --- a/Model/Applications/InvidiousAPI.swift +++ b/Model/Applications/InvidiousAPI.swift @@ -247,27 +247,27 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI { } func feed(_ page: Int?) -> Resource? { - resource(baseURL: account.url, path: "\(Self.basePath)/auth/feed") + resourceWithAuthCheck(baseURL: account.url, path: "\(Self.basePath)/auth/feed") .withParam("page", String(page ?? 1)) } var feed: Resource? { - resource(baseURL: account.url, path: basePathAppending("auth/feed")) + resourceWithAuthCheck(baseURL: account.url, path: basePathAppending("auth/feed")) } var subscriptions: Resource? { - resource(baseURL: account.url, path: basePathAppending("auth/subscriptions")) + resourceWithAuthCheck(baseURL: account.url, path: basePathAppending("auth/subscriptions")) } func subscribe(_ channelID: String, onCompletion: @escaping () -> Void = {}) { - resource(baseURL: account.url, path: basePathAppending("auth/subscriptions")) + resourceWithAuthCheck(baseURL: account.url, path: basePathAppending("auth/subscriptions")) .child(channelID) .request(.post) .onCompletion { _ in onCompletion() } } func unsubscribe(_ channelID: String, onCompletion: @escaping () -> Void) { - resource(baseURL: account.url, path: basePathAppending("auth/subscriptions")) + resourceWithAuthCheck(baseURL: account.url, path: basePathAppending("auth/subscriptions")) .child(channelID) .request(.delete) .onCompletion { _ in onCompletion() } @@ -308,11 +308,11 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI { return nil } - return resource(baseURL: account.url, path: basePathAppending("auth/playlists")) + return resourceWithAuthCheck(baseURL: account.url, path: basePathAppending("auth/playlists")) } func playlist(_ id: String) -> Resource? { - resource(baseURL: account.url, path: basePathAppending("auth/playlists/\(id)")) + resourceWithAuthCheck(baseURL: account.url, path: basePathAppending("auth/playlists/\(id)")) } func playlistVideos(_ id: String) -> Resource? { @@ -556,6 +556,30 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI { ) } + // Determines if the request requires Basic Auth credentials to be removed + private func needsBasicAuthRemoval(for path: String) -> Bool { + return path.hasPrefix("\(Self.basePath)/auth/") + } + + // Creates a resource URL with consideration for removing Basic Auth credentials + private func createResourceURL(baseURL: URL, path: String) -> URL { + var resourceURL = baseURL + + // Remove Basic Auth credentials if required + if needsBasicAuthRemoval(for: path), var urlComponents = URLComponents(url: baseURL, resolvingAgainstBaseURL: false) { + urlComponents.user = nil + urlComponents.password = nil + resourceURL = urlComponents.url ?? baseURL + } + + return resourceURL.appendingPathComponent(path) + } + + func resourceWithAuthCheck(baseURL: URL, path: String) -> Resource { + let sanitizedURL = createResourceURL(baseURL: baseURL, path: path) + return super.resource(absoluteURL: sanitizedURL) + } + private func extractThumbnails(from details: JSON) -> [Thumbnail] { details["videoThumbnails"].arrayValue.compactMap { json in guard let url = json["url"].url, @@ -570,7 +594,7 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI { // with an incorrect scheme or a missing port. components.scheme = accountUrlComponents.scheme components.port = accountUrlComponents.port - + // If basic HTTP authentication is used, // the username and password need to be prepended to the URL. components.user = accountUrlComponents.user From f0d581d51252aac0c826f5984e11f0ce85f017d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Wed, 28 Aug 2024 18:05:40 +0200 Subject: [PATCH 6/7] remove autocorrect from location url TextField MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Toni Förster --- Shared/Settings/InstanceForm.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Shared/Settings/InstanceForm.swift b/Shared/Settings/InstanceForm.swift index c78e1056..c74bb052 100644 --- a/Shared/Settings/InstanceForm.swift +++ b/Shared/Settings/InstanceForm.swift @@ -86,6 +86,7 @@ struct InstanceForm: View { .autocapitalization(.none) .keyboardType(.URL) #endif + .disableAutocorrection(true) #if os(tvOS) VStack { From 13382270d5eea4c7e112ce92e5c77c1553beb617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Sat, 31 Aug 2024 02:50:56 +0200 Subject: [PATCH 7/7] Revert "fixed some potential crashes" This reverts commit bde9aade1173a8a466e3d54e2adc39bea49efe97. --- Model/Store.swift | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Model/Store.swift b/Model/Store.swift index 3f27eadc..67e0eee8 100644 --- a/Model/Store.swift +++ b/Model/Store.swift @@ -20,16 +20,10 @@ final class Store: ResourceObserver, ObservableObject { } func replace(_ items: Data) { - // Ensure the change happens on the main thread - DispatchQueue.main.async { - self.all = items - } + all = items } func clear() { - // Ensure clearing happens on the main thread - DispatchQueue.main.async { - self.all = nil - } + all = nil } }