Update Ghostgram features

This commit is contained in:
ichmagmaus 812
2026-03-07 18:15:32 +01:00
parent 1a3303b059
commit 24a7ec39d9
902 changed files with 148302 additions and 62355 deletions
+17
View File
@@ -0,0 +1,17 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "SGKeychainBackupManager",
module_name = "SGKeychainBackupManager",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
],
visibility = [
"//visibility:public",
],
)
@@ -0,0 +1,131 @@
import Foundation
import Security
public enum KeychainError: Error {
case duplicateEntry
case unknown(OSStatus)
case itemNotFound
case invalidItemFormat
}
public class KeychainBackupManager {
public static let shared = KeychainBackupManager()
private let service = "\(Bundle.main.bundleIdentifier!).sessionsbackup"
private init() {}
// MARK: - Save Credentials
public func saveSession(id: String, _ session: Data) throws {
// Create query dictionary
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: id,
kSecValueData as String: session,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
]
// Add to keychain
let status = SecItemAdd(query as CFDictionary, nil)
if status == errSecDuplicateItem {
// Item already exists, update it
let updateQuery: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: id
]
let attributesToUpdate: [String: Any] = [
kSecValueData as String: session
]
let updateStatus = SecItemUpdate(updateQuery as CFDictionary,
attributesToUpdate as CFDictionary)
if updateStatus != errSecSuccess {
throw KeychainError.unknown(updateStatus)
}
} else if status != errSecSuccess {
throw KeychainError.unknown(status)
}
}
// MARK: - Retrieve Credentials
public func retrieveSession(for id: String) throws -> Data {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: id,
kSecReturnData as String: true
]
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
guard status == errSecSuccess, let sessionData = result as? Data else {
throw KeychainError.itemNotFound
}
return sessionData
}
// MARK: - Delete Credentials
public func deleteSession(for id: String) throws {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: id
]
let status = SecItemDelete(query as CFDictionary)
if status != errSecSuccess && status != errSecItemNotFound {
throw KeychainError.unknown(status)
}
}
// MARK: - Retrieve All Accounts
public func getAllSessons() throws -> [Data] {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitAll
]
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
if status == errSecItemNotFound {
return []
}
guard status == errSecSuccess,
let credentialsDataArray = result as? [Data] else {
throw KeychainError.unknown(status)
}
return credentialsDataArray
}
// MARK: - Delete All Sessions
public func deleteAllSessions() throws {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service
]
let status = SecItemDelete(query as CFDictionary)
// If no items were found, that's fine - just return
if status == errSecItemNotFound {
return
}
// For any other error, throw
if status != errSecSuccess {
throw KeychainError.unknown(status)
}
}
}