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

133 lines
4 KiB
Swift

//
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
@objc(StickerPackInfo)
public class StickerPackInfo: MTLModel {
// Exposed to Objective-C and made optional for MTLModel serialization.
@objc
public var packId: Data!
@objc
public var packKey: Data!
@objc
public init(packId: Data, packKey: Data) {
owsPrecondition(!packId.isEmpty && packKey.count == StickerManager.packKeyLength)
self.packId = packId
self.packKey = packKey
super.init()
}
@objc
public var asKey: String { packId.hexadecimalString }
@objc(parsePackIdHex:packKeyHex:)
public class func parse(packIdHex: String?, packKeyHex: String?) -> StickerPackInfo? {
guard let packIdHex, !packIdHex.isEmpty else {
Logger.warn("Invalid packIdHex")
return nil
}
guard let packKeyHex, !packKeyHex.isEmpty else {
Logger.warn("Invalid packKeyHex")
return nil
}
return parse(packId: Data.data(fromHex: packIdHex), packKey: Data.data(fromHex: packKeyHex))
}
public class func parse(packId: Data?, packKey: Data?) -> StickerPackInfo? {
guard let packId, !packId.isEmpty else {
Logger.warn("Invalid packId")
return nil
}
guard let packKey, packKey.count == StickerManager.packKeyLength else {
Logger.warn("Invalid packKey")
return nil
}
return StickerPackInfo(packId: packId, packKey: packKey)
}
public func shareUrl() -> String {
let packIdHex = packId.hexadecimalString
let packKeyHex = packKey.hexadecimalString
return "https://signal.art/addstickers/#pack_id=\(packIdHex)&pack_key=\(packKeyHex)"
}
@objc(isStickerPackShareUrl:)
public class func isStickerPackShare(_ url: URL) -> Bool {
url.scheme == "https" &&
url.user == nil &&
url.password == nil &&
url.host == "signal.art" &&
url.port == nil &&
url.path == "/addstickers"
}
@objc(parseStickerPackShareUrl:)
public class func parseStickerPackShare(_ url: URL) -> StickerPackInfo? {
guard
isStickerPackShare(url),
let components = URLComponents(string: url.absoluteString)
else {
owsFail("Invalid URL.")
}
guard
let fragment = components.fragment,
let queryItems = parseAsQueryItems(string: fragment)
else {
Logger.warn("No fragment to parse as query items")
return nil
}
var packIdHex: String?
var packKeyHex: String?
for queryItem in queryItems {
switch queryItem.name {
case "pack_id":
if packIdHex != nil {
Logger.warn("Duplicate pack_id. Using the newest one")
}
packIdHex = queryItem.value
case "pack_key":
if packKeyHex != nil {
Logger.warn("Duplicate pack_key. Using the newest one")
}
packKeyHex = queryItem.value
default:
Logger.warn("Unknown query item: \(queryItem.name)")
}
}
return parse(packIdHex: packIdHex, packKeyHex: packKeyHex)
}
private class func parseAsQueryItems(string: String) -> [URLQueryItem]? {
guard let fakeUrl = URL(string: "http://example.com?\(string)") else {
return nil
}
return URLComponents(string: fakeUrl.absoluteString)?.queryItems
}
public override var description: String { packId.hexadecimalString }
// MARK: - MTLModel
@objc
public override init() {
super.init()
}
@objc
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
@objc
public required init(dictionary dictionaryValue: [String: Any]!) throws {
try super.init(dictionary: dictionaryValue)
}
}