mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-21 16:36:50 +00:00
fix(security): block automatic metadata fetch for private IP addresses
This commit is contained in:
@@ -83,7 +83,7 @@ struct AddDownloadsView: View {
|
|||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
Spacer()
|
Spacer()
|
||||||
Button {
|
Button {
|
||||||
refreshMetadata(for: linkText)
|
refreshMetadata(for: linkText, isAutoFetch: false)
|
||||||
} label: {
|
} label: {
|
||||||
Label("Refresh Metadata", systemImage: "arrow.clockwise")
|
Label("Refresh Metadata", systemImage: "arrow.clockwise")
|
||||||
}
|
}
|
||||||
@@ -422,7 +422,7 @@ struct AddDownloadsView: View {
|
|||||||
try? await Task.sleep(for: .milliseconds(350))
|
try? await Task.sleep(for: .milliseconds(350))
|
||||||
guard !Task.isCancelled else { return }
|
guard !Task.isCancelled else { return }
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
refreshMetadata(for: text)
|
refreshMetadata(for: text, isAutoFetch: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,7 +445,7 @@ struct AddDownloadsView: View {
|
|||||||
controller.pendingReferer = nil
|
controller.pendingReferer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
private func refreshMetadata(for text: String) {
|
private func refreshMetadata(for text: String, isAutoFetch: Bool) {
|
||||||
let urls = DownloadURLParser.parse(text)
|
let urls = DownloadURLParser.parse(text)
|
||||||
metadataTask?.cancel()
|
metadataTask?.cancel()
|
||||||
|
|
||||||
@@ -476,7 +476,8 @@ struct AddDownloadsView: View {
|
|||||||
for: url,
|
for: url,
|
||||||
settings: settings,
|
settings: settings,
|
||||||
credentials: metadataCredentials(for: url),
|
credentials: metadataCredentials(for: url),
|
||||||
transferOptions: transferOptions
|
transferOptions: transferOptions,
|
||||||
|
isAutoFetch: isAutoFetch
|
||||||
)
|
)
|
||||||
loaded.append(item)
|
loaded.append(item)
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ enum DownloadMetadataFetcher {
|
|||||||
for url: URL,
|
for url: URL,
|
||||||
settings: AppSettings,
|
settings: AppSettings,
|
||||||
credentials: DownloadCredentials? = nil,
|
credentials: DownloadCredentials? = nil,
|
||||||
transferOptions: DownloadTransferOptions = DownloadTransferOptions()
|
transferOptions: DownloadTransferOptions = DownloadTransferOptions(),
|
||||||
|
isAutoFetch: Bool = false
|
||||||
) async -> PendingDownload {
|
) async -> PendingDownload {
|
||||||
let initialName = FileClassifier.fileName(from: url)
|
let initialName = FileClassifier.fileName(from: url)
|
||||||
let initialCategory = FileClassifier.category(forFileName: initialName)
|
let initialCategory = FileClassifier.category(forFileName: initialName)
|
||||||
@@ -53,6 +54,11 @@ enum DownloadMetadataFetcher {
|
|||||||
return pending
|
return pending
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isAutoFetch, let host = url.host, isPrivateHost(host) {
|
||||||
|
pending.state = .loaded
|
||||||
|
return pending
|
||||||
|
}
|
||||||
|
|
||||||
var request = URLRequest(url: url)
|
var request = URLRequest(url: url)
|
||||||
request.httpMethod = "HEAD"
|
request.httpMethod = "HEAD"
|
||||||
request.timeoutInterval = 12
|
request.timeoutInterval = 12
|
||||||
@@ -122,6 +128,32 @@ enum DownloadMetadataFetcher {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static func isPrivateHost(_ host: String) -> Bool {
|
||||||
|
let h = host.lowercased()
|
||||||
|
if h == "localhost" || h.hasSuffix(".local") { return true }
|
||||||
|
if !h.contains(".") && !h.contains(":") { return true }
|
||||||
|
|
||||||
|
let parts = h.split(separator: ".")
|
||||||
|
if parts.count == 4, let first = Int(parts[0]), let second = Int(parts[1]) {
|
||||||
|
if first == 127 || first == 10 || (first == 192 && second == 168) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if first == 172 && (16...31).contains(second) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if first == 169 && second == 254 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.contains(":") {
|
||||||
|
if h == "[::1]" || h.hasPrefix("[fc") || h.hasPrefix("[fd") || h.hasPrefix("[fe8") || h.hasPrefix("[fe9") || h.hasPrefix("[fea") || h.hasPrefix("[feb") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ByteFormatter {
|
enum ByteFormatter {
|
||||||
|
|||||||
Reference in New Issue
Block a user