wip
This commit is contained in:
parent
5f5e20b462
commit
d0cbe63eb1
|
@ -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)
|
||||
|
|
|
@ -117,28 +117,34 @@ extension Client {
|
|||
|
||||
var msg = chat.createMessage(text: message.body ?? "??", id: message.id)
|
||||
msg.oob = message.oobUrl
|
||||
msg = try await encryptMessage(msg)
|
||||
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 encrypted = Data()
|
||||
var tag = Data()
|
||||
guard AESGSMEngine.shared.encrypt(iv: iv, key: key, message: data, output: &encrypted, tag: &tag) else {
|
||||
throw AppError.securityError
|
||||
}
|
||||
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 {
|
||||
throw AppError.securityError
|
||||
}
|
||||
|
||||
// attach tag to end of encrypted data
|
||||
encrypted.append(tag)
|
||||
data = encrypted
|
||||
// attach tag to end of encrypted data
|
||||
encrypted.append(tag)
|
||||
data = encrypted
|
||||
}
|
||||
|
||||
// upload
|
||||
let httpModule = connection.module(HttpFileUploadModule.self)
|
||||
|
@ -164,15 +170,19 @@ extension Client {
|
|||
let (_, response) = try await URLSession.shared.data(for: request)
|
||||
switch response {
|
||||
case let httpResponse as HTTPURLResponse where httpResponse.statusCode == 201:
|
||||
guard var parts = URLComponents(url: slot.getUri, resolvingAgainstBaseURL: true) else {
|
||||
throw URLError(.badServerResponse)
|
||||
if needEncrypt {
|
||||
guard var parts = URLComponents(url: slot.getUri, resolvingAgainstBaseURL: true) else {
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
parts.scheme = "aesgcm"
|
||||
parts.fragment = (iv + key).map { String(format: "%02x", $0) }.joined()
|
||||
guard let shareUrl = parts.url else {
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
return shareUrl.absoluteString
|
||||
} else {
|
||||
return slot.getUri.absoluteString
|
||||
}
|
||||
parts.scheme = "aesgcm"
|
||||
parts.fragment = (iv + key).map { String(format: "%02x", $0) }.joined()
|
||||
guard let shareUrl = parts.url else {
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
return shareUrl.absoluteString
|
||||
|
||||
default:
|
||||
throw URLError(.badServerResponse)
|
||||
|
|
|
@ -14,6 +14,7 @@ struct Chat: DBStorable {
|
|||
var account: String
|
||||
var participant: String
|
||||
var type: ConversationType
|
||||
var encrypted: Bool
|
||||
}
|
||||
|
||||
extension Chat: Equatable {}
|
||||
|
|
|
@ -50,7 +50,7 @@ extension Message {
|
|||
secure = true
|
||||
|
||||
case .successTransportKey:
|
||||
break
|
||||
return nil
|
||||
|
||||
case .failure(let error):
|
||||
logIt(.error, "Error decoding omemo message: \(error)")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue