Swiftgram/submodules/SyncCore/Sources/SecretChatKeychain.swift
2019-11-01 17:11:12 +04:00

185 lines
5.9 KiB
Swift

import Foundation
import Postbox
public enum SecretChatKeyValidity: PostboxCoding, Equatable {
case indefinite
case sequenceBasedIndexRange(fromCanonicalIndex: Int32)
public init(decoder: PostboxDecoder) {
switch decoder.decodeInt32ForKey("r", orElse: 0) {
case 0:
self = .indefinite
case 1:
self = .sequenceBasedIndexRange(fromCanonicalIndex: decoder.decodeInt32ForKey("l", orElse: 0))
default:
assertionFailure()
self = .sequenceBasedIndexRange(fromCanonicalIndex: Int32.max)
}
}
public func encode(_ encoder: PostboxEncoder) {
switch self {
case .indefinite:
encoder.encodeInt32(0, forKey: "r")
case let .sequenceBasedIndexRange(fromCanonicalIndex):
encoder.encodeInt32(1, forKey: "r")
encoder.encodeInt32(fromCanonicalIndex, forKey: "l")
}
}
public static func ==(lhs: SecretChatKeyValidity, rhs: SecretChatKeyValidity) -> Bool {
switch lhs {
case .indefinite:
if case .indefinite = rhs {
return true
} else {
return false
}
case let .sequenceBasedIndexRange(fromCanonicalIndex):
if case .sequenceBasedIndexRange(fromCanonicalIndex) = rhs {
return true
} else {
return false
}
}
}
}
public final class SecretChatKey: PostboxCoding, Equatable {
public let fingerprint: Int64
public let key: MemoryBuffer
public let validity: SecretChatKeyValidity
public let useCount: Int32
public init(fingerprint: Int64, key: MemoryBuffer, validity: SecretChatKeyValidity, useCount: Int32) {
self.fingerprint = fingerprint
self.key = key
self.validity = validity
self.useCount = useCount
}
public init(decoder: PostboxDecoder) {
self.fingerprint = decoder.decodeInt64ForKey("f", orElse: 0)
self.key = decoder.decodeBytesForKey("k")!
self.validity = decoder.decodeObjectForKey("v", decoder: { SecretChatKeyValidity(decoder: $0) }) as! SecretChatKeyValidity
self.useCount = decoder.decodeInt32ForKey("u", orElse: 0)
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt64(self.fingerprint, forKey: "f")
encoder.encodeBytes(self.key, forKey: "k")
encoder.encodeObject(self.validity, forKey: "v")
encoder.encodeInt32(self.useCount, forKey: "u")
}
public func withIncrementedUseCount() -> SecretChatKey {
return SecretChatKey(fingerprint: self.fingerprint, key: self.key, validity: self.validity, useCount: self.useCount + 1)
}
public static func ==(lhs: SecretChatKey, rhs: SecretChatKey) -> Bool {
if lhs.fingerprint != rhs.fingerprint {
return false
}
if lhs.validity != rhs.validity {
return false
}
if lhs.useCount != rhs.useCount {
return false
}
return true
}
}
public final class SecretChatKeychain: PostboxCoding, Equatable {
public let keys: [SecretChatKey]
public init(keys: [SecretChatKey]) {
self.keys = keys
}
public init(decoder: PostboxDecoder) {
self.keys = decoder.decodeObjectArrayWithDecoderForKey("k")
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeObjectArray(self.keys, forKey: "k")
}
public func key(fingerprint: Int64) -> SecretChatKey? {
for key in self.keys {
if key.fingerprint == fingerprint {
return key
}
}
return nil
}
public func indefinitelyValidKey() -> SecretChatKey? {
for key in self.keys {
if case .indefinite = key.validity {
return key
}
}
return nil
}
public func latestKey(validForSequenceBasedCanonicalIndex index: Int32) -> SecretChatKey? {
var maxFromCanonicalIndex: (Int, Int32)?
for i in 0 ..< self.keys.count {
switch self.keys[i].validity {
case .indefinite:
break
case let .sequenceBasedIndexRange(fromCanonicalIndex):
if index >= fromCanonicalIndex {
if maxFromCanonicalIndex == nil || maxFromCanonicalIndex!.1 < fromCanonicalIndex {
maxFromCanonicalIndex = (i, fromCanonicalIndex)
}
}
}
}
if let (keyIndex, _) = maxFromCanonicalIndex {
return self.keys[keyIndex]
}
for i in 0 ..< self.keys.count {
switch self.keys[i].validity {
case .indefinite:
return self.keys[i]
default:
break
}
}
return nil
}
public func withUpdatedKey(fingerprint: Int64, _ f: (SecretChatKey?) -> SecretChatKey?) -> SecretChatKeychain {
var keys = self.keys
var found = false
for i in 0 ..< keys.count {
if keys[i].fingerprint == fingerprint {
found = true
let updatedKey = f(keys[i])
if let updatedKey = updatedKey {
keys[i] = updatedKey
} else {
keys.remove(at: i)
}
break
}
}
if !found {
let updatedKey = f(nil)
if let updatedKey = updatedKey {
keys.append(updatedKey)
}
}
return SecretChatKeychain(keys: keys)
}
public static func ==(lhs: SecretChatKeychain, rhs: SecretChatKeychain) -> Bool {
return lhs.keys == rhs.keys
}
}