TM-SGNL-iOS/SignalServiceKit/Devices/OWSDevice.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

164 lines
5 KiB
Swift

//
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public import GRDB
@available(swift, obsoleted: 1.0)
@objcMembers
public class OWSDeviceObjc: NSObject {
public static let primaryDeviceId: UInt32 = OWSDevice.primaryDeviceId
}
public final class OWSDevice: SDSCodableModel, Decodable {
public static let primaryDeviceId: UInt32 = 1
public static let databaseTableName: String = "model_OWSDevice"
public static var recordType: UInt { SDSRecordType.device.rawValue }
public enum CodingKeys: String, CodingKey, ColumnExpression, CaseIterable {
case id
case recordType
case uniqueId
case deviceId
case encryptedName = "name"
case createdAt
case lastSeenAt
}
public var id: RowId?
public let uniqueId: String
public let deviceId: Int
public var encryptedName: String?
public let createdAt: Date
public let lastSeenAt: Date
init(
deviceId: Int,
encryptedName: String?,
createdAt: Date,
lastSeenAt: Date
) {
self.uniqueId = UUID().uuidString
self.deviceId = deviceId
self.encryptedName = encryptedName
self.createdAt = createdAt
self.lastSeenAt = lastSeenAt
}
#if DEBUG
public static func previewItem(id: Int) -> OWSDevice {
OWSDevice(
deviceId: id,
encryptedName: nil,
createdAt: Date().addingTimeInterval(-86_400 * TimeInterval(Int.random(in: 10...20))),
lastSeenAt: Date().addingTimeInterval(-86_400 * TimeInterval(Int.random(in: 0...10)))
)
}
#endif
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let decodedRecordType = try container.decode(UInt.self, forKey: .recordType)
owsAssertDebug(decodedRecordType == Self.recordType, "Unexpectedly decoded record with wrong type!")
id = try container.decodeIfPresent(RowId.self, forKey: .id)
uniqueId = try container.decode(String.self, forKey: .uniqueId)
deviceId = try container.decode(Int.self, forKey: .deviceId)
encryptedName = try container.decodeIfPresent(String.self, forKey: .encryptedName)
createdAt = try container.decode(Date.self, forKey: .createdAt)
lastSeenAt = try container.decode(Date.self, forKey: .lastSeenAt)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(Self.recordType, forKey: .recordType)
try id.map { try container.encode($0, forKey: .id) }
try container.encode(uniqueId, forKey: .uniqueId)
try container.encode(deviceId, forKey: .deviceId)
try container.encodeIfPresent(encryptedName, forKey: .encryptedName)
try container.encode(createdAt, forKey: .createdAt)
try container.encode(lastSeenAt, forKey: .lastSeenAt)
}
}
public extension OWSDevice {
func displayName(
identityManager: OWSIdentityManager,
tx: DBReadTransaction
) -> String {
if let encryptedName = self.encryptedName {
if let identityKeyPair = identityManager.identityKeyPair(for: .aci, tx: tx) {
do {
return try DeviceNames.decryptDeviceName(
base64String: encryptedName,
identityKeyPair: identityKeyPair.keyPair
)
} catch let error {
Logger.error("Failed to decrypt device name: \(error). Is this a legacy device name?")
}
}
return encryptedName
}
if deviceId == Self.primaryDeviceId {
return OWSLocalizedString(
"DEVICE_NAME_THIS_DEVICE",
comment: "A label for this device in the device list."
)
}
return OWSLocalizedString(
"DEVICE_NAME_UNNAMED_DEVICE",
comment: "A label for an unnamed device in the device list."
)
}
var isPrimaryDevice: Bool {
deviceId == Self.primaryDeviceId
}
var isLinkedDevice: Bool {
!isPrimaryDevice
}
}
// MARK: - Replace all
public extension OWSDevice {
/// Update our persisted devices to match the given devices.
///
/// - Returns
/// `true` if any devices were added or removed, and `false` otherwise.
static func replaceAll(
with newDevices: [OWSDevice],
transaction: SDSAnyWriteTransaction
) -> Bool {
let existingDevices = anyFetchAll(transaction: transaction)
for existingDevice in existingDevices {
existingDevice.anyRemove(transaction: transaction)
}
for newDevice in newDevices {
newDevice.anyInsert(transaction: transaction)
}
let existingDeviceIds = Set(existingDevices.map { $0.deviceId })
let newDeviceIds = Set(newDevices.map { $0.deviceId })
return !newDeviceIds.symmetricDifference(existingDeviceIds).isEmpty
}
}