This commit is contained in:
fmodf 2024-09-19 17:14:05 +02:00
parent 5f5e20b462
commit d0cbe63eb1
8 changed files with 75 additions and 27 deletions

View file

@ -51,7 +51,8 @@ final class ClientMartinChatsManager: Martin.ChatManager {
id: UUID().uuidString,
account: context.userBareJid.stringValue,
participant: with.stringValue,
type: .chat
type: .chat,
encrypted: UserSettings.secureChatsByDefault
)
try Database.shared.dbQueue.write { db in
try chat.save(db)

View file

@ -117,19 +117,24 @@ extension Client {
var msg = chat.createMessage(text: message.body ?? "??", id: message.id)
msg.oob = message.oobUrl
if message.secure {
msg = try await encryptMessage(msg)
}
try await chat.send(message: msg)
}
func uploadFile(_ localURL: URL) async throws -> String {
func uploadFile(_ localURL: URL, needEncrypt: Bool) async throws -> String {
// get data from file
guard var data = try? Data(contentsOf: localURL) else {
throw AppError.noData
}
// encrypt data if needed
let key = try AESGSMEngine.generateKey()
let iv = try AESGSMEngine.generateIV()
var key = Data()
var iv = Data()
if needEncrypt {
key = try AESGSMEngine.generateKey()
iv = try AESGSMEngine.generateIV()
var encrypted = Data()
var tag = Data()
guard AESGSMEngine.shared.encrypt(iv: iv, key: key, message: data, output: &encrypted, tag: &tag) else {
@ -139,6 +144,7 @@ extension Client {
// attach tag to end of encrypted data
encrypted.append(tag)
data = encrypted
}
// upload
let httpModule = connection.module(HttpFileUploadModule.self)
@ -164,6 +170,7 @@ extension Client {
let (_, response) = try await URLSession.shared.data(for: request)
switch response {
case let httpResponse as HTTPURLResponse where httpResponse.statusCode == 201:
if needEncrypt {
guard var parts = URLComponents(url: slot.getUri, resolvingAgainstBaseURL: true) else {
throw URLError(.badServerResponse)
}
@ -173,6 +180,9 @@ extension Client {
throw URLError(.badServerResponse)
}
return shareUrl.absoluteString
} else {
return slot.getUri.absoluteString
}
default:
throw URLError(.badServerResponse)

View file

@ -14,6 +14,7 @@ struct Chat: DBStorable {
var account: String
var participant: String
var type: ConversationType
var encrypted: Bool
}
extension Chat: Equatable {}

View file

@ -50,7 +50,7 @@ extension Message {
secure = true
case .successTransportKey:
break
return nil
case .failure(let error):
logIt(.error, "Error decoding omemo message: \(error)")

View file

@ -97,6 +97,10 @@ extension Database {
try db.alter(table: "messages") { table in
table.add(column: "secure", .boolean).notNull().defaults(to: false)
}
try db.alter(table: "chats") { table in
table.add(column: "encrypted", .boolean).notNull().defaults(to: false)
}
}
// return migrator

View file

@ -12,8 +12,10 @@ final class AttachmentsStore: ObservableObject {
private let client: Client
private let roster: Roster
private var secured: Bool = false
private var messagesCancellable: AnyCancellable?
private var chatCancellable: AnyCancellable?
private var processing: Set<String> = []
init(roster: Roster, client: Client) {
@ -62,7 +64,7 @@ extension AttachmentsStore {
var message = Message.blank
message.from = roster.bareJid
message.to = roster.contactBareJid
message.secure = true
message.secure = secured
switch item.type {
case .photo:
@ -111,7 +113,7 @@ extension AttachmentsStore {
var message = Message.blank
message.from = roster.bareJid
message.to = roster.contactBareJid
message.secure = true
message.secure = secured
let localName: String
let msgType: AttachmentType
@ -177,7 +179,7 @@ extension AttachmentsStore {
var message = Message.blank
message.from = roster.bareJid
message.to = roster.contactBareJid
message.secure = true
message.secure = secured
message.contentType = .attachment(
Attachment(
type: localName.attachmentType,
@ -241,6 +243,18 @@ private extension AttachmentsStore {
}
}
}
chatCancellable = ValueObservation.tracking(Chat
.filter(Column("bareJid") == roster.bareJid && Column("contactBareJid") == roster.contactBareJid)
.fetchOne
)
.publisher(in: Database.shared.dbQueue, scheduling: .immediate)
.receive(on: DispatchQueue.main)
.sink { _ in
} receiveValue: { [weak self] chat in
guard let self = self else { return }
self.secured = chat?.encrypted ?? false
}
}
}
@ -256,7 +270,7 @@ extension AttachmentsStore {
guard let localName = attachment.localPath else {
throw AppError.invalidLocalName
}
let remotePath = try await client.uploadFile(localName)
let remotePath = try await client.uploadFile(localName, needEncrypt: message.secure)
message.contentType = .attachment(
Attachment(
type: attachment.type,

View file

@ -10,8 +10,10 @@ final class MessagesStore: ObservableObject {
private(set) var roster: Roster
private let client: Client
private var secured: Bool = false
private var messagesCancellable: AnyCancellable?
private var chatCancellable: AnyCancellable?
private let archiver = ArchiveMessageFetcher()
init(roster: Roster, client: Client) {
@ -29,7 +31,7 @@ extension MessagesStore {
msg.from = roster.bareJid
msg.to = roster.contactBareJid
msg.body = message
msg.secure = true
msg.secure = secured
// store as pending on db, and send
do {
@ -72,6 +74,18 @@ private extension MessagesStore {
await self.archiver.initialFetch(messages, self.roster, self.client)
}
}
chatCancellable = ValueObservation.tracking(Chat
.filter(Column("bareJid") == roster.bareJid && Column("contactBareJid") == roster.contactBareJid)
.fetchOne
)
.publisher(in: Database.shared.dbQueue, scheduling: .immediate)
.receive(on: DispatchQueue.main)
.sink { _ in
} receiveValue: { [weak self] chat in
guard let self = self else { return }
self.secured = chat?.encrypted ?? false
}
}
}

View file

@ -25,8 +25,12 @@ struct Storage<T> {
// Storage
private let kOmemoDeviceId = "conversations.classic.user.defaults.omemoDeviceId"
private let kSecureChatsByDefault = "conversations.classic.user.defaults.secureChatsByDefault"
enum UserSettings {
@Storage(key: kOmemoDeviceId, defaultValue: 0)
static var omemoDeviceId: UInt32
@Storage(key: kSecureChatsByDefault, defaultValue: false)
static var secureChatsByDefault: Bool
}