Warn when signing in to dangerous instances

This commit is contained in:
Lumaa 2024-02-16 16:21:46 +01:00
parent d8bfc0a4c3
commit 97254d0829
3 changed files with 265 additions and 0 deletions

View File

@ -3,6 +3,45 @@
import Foundation
public struct Instance: Codable, Sendable {
static let blocklistUrl: URL? = URL(string: "https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/_unified_tier2_blocklist.csv")
@MainActor
static func getBlocklist() -> [String] {
var final: [String] = []
//locate the file you want to use
guard let filelink = Instance.blocklistUrl else {
return []
}
//convert that file into one long string
var data = ""
do {
data = try String(contentsOf: filelink)
} catch {
print(error)
return []
}
//now split that string into an array of "rows" of data. Each row is a string.
var rows = data.components(separatedBy: "\n")
//if you have a header row, remove it here
rows.removeFirst()
//now loop around each row, and split it into each of its columns
for row in rows {
let columns = row.components(separatedBy: ",")
//check that we have enough columns
if columns.count > 0 {
let instanceUrl = columns[0]
final.append(instanceUrl)
}
}
return final
}
public struct Stats: Codable, Sendable {
public let userCount: Int
public let statusCount: Int

View File

@ -383,6 +383,22 @@
}
}
},
"activity.messages.read" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Mark as read"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Marquer comme lu"
}
}
}
},
"activity.no-notifications" : {
"localizations" : {
"en" : {
@ -743,6 +759,70 @@
}
}
},
"login.instance.unsafe" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "This instance is dangerous"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Cette instance est dangereuse"
}
}
}
},
"login.instance.unsafe.agree" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "I agree"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Je suis d'accord"
}
}
}
},
"login.instance.unsafe.description" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The instance has been detected to be dangerous, Threaded does not take responsibility for any content posted or seen on this instance and will not provide support. Do you agree to take FULL responsibility?"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Cette instance a été détectée comme étant dangereuse, Threaded ne prend pas la responsabilité pour tout contenu posté ou vu dans cette instance et ne fournira pas d'aide. Êtes-vous d'accord pour prendre la TOTALE responsabilité ?"
}
}
}
},
"login.instance.unsafe.disagree" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "I disagree"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Je suis pas d'accord"
}
}
}
},
"login.mastodon" : {
"localizations" : {
"en" : {
@ -1479,6 +1559,70 @@
}
}
},
"status.action.bookmark" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Bookmark"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Placer un signet"
}
}
}
},
"status.action.like" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Like"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Aimer"
}
}
}
},
"status.action.unbookmark" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Unbookmark"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Enlever le signet"
}
}
}
},
"status.action.unlike" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Unlike"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Plus aimer"
}
}
}
},
"status.editing" : {
"localizations" : {
"en" : {

View File

@ -9,9 +9,16 @@ struct AddInstanceView: View {
// Instance URL and verify
@State private var instanceUrl: String = ""
@State private var verifying: Bool = false
@State private var verified: Bool = false
@State private var verifyError: Bool = false
@State private var blockList: [String] = []
@State private var responsability: Bool = false
@State private var showingResponsability: Bool = false
@State private var agreedResponsability: Bool = false
@State private var instanceInfo: Instance?
@State private var signInClient: Client?
@ -87,6 +94,36 @@ struct AddInstanceView: View {
}
}
}
.task {
withAnimation {
verifying = true
}
blockList = Instance.getBlocklist()
withAnimation {
verifying = false
}
}
.alert("login.instance.unsafe", isPresented: $showingResponsability, actions: {
Button(role: .destructive) {
responsability = true
agreedResponsability = true
showingResponsability.toggle()
} label: {
Text("login.instance.unsafe.agree")
}
Button(role: .cancel) {
responsability = true
agreedResponsability = false
showingResponsability.toggle()
} label: {
Text("login.instance.unsafe.disagree")
}
}, message: {
Text("login.instance.unsafe.description")
})
.scrollContentBackground(.hidden)
.background(Color.appBackground)
.onChange(of: instanceUrl) { _, newValue in
@ -106,6 +143,38 @@ struct AddInstanceView: View {
.replacingOccurrences(of: "http://", with: "")
.replacingOccurrences(of: "https://", with: "")
if !isInstanceSafe() {
if responsability == false && agreedResponsability == false {
responsability = true
agreedResponsability = false
showingResponsability = true
withAnimation {
verifying = false
verified = false
verifyError = false
}
return
} else if responsability == true && agreedResponsability == true {
showingResponsability = false
} else if responsability == true && agreedResponsability == false {
showingResponsability = true
withAnimation {
verifying = false
verified = false
verifyError = false
}
return
}
} else {
responsability = false
agreedResponsability = false
UserDefaults.standard.removeObject(forKey: "unsafe")
}
let client = Client(server: cleanInstance)
Task {
@ -147,6 +216,12 @@ struct AddInstanceView: View {
return
}
if agreedResponsability && responsability {
UserDefaults.standard.setValue(true, forKey: "unsafe")
} else {
UserDefaults.standard.removeObject(forKey: "unsafe")
}
do {
let oauthToken = try await client.continueOauthFlow(url: url)
let client = Client(server: client.server, oauthToken: oauthToken)
@ -163,6 +238,13 @@ struct AddInstanceView: View {
print(error)
}
}
/// Is the user input instance URL a safe instance
/// - returns: True, if the instance isn't consider as dangerous
private func isInstanceSafe() -> Bool {
let unsafe = blockList.contains(instanceUrl.trimmingCharacters(in: .whitespacesAndNewlines))
return !unsafe
}
}
#Preview {