Skip to content

Commit

Permalink
Fix: Support for checking the status of the credential
Browse files Browse the repository at this point in the history
  • Loading branch information
josmilan authored Dec 5, 2024
1 parent 6fe67ea commit 63d8696
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 0 deletions.
83 changes: 83 additions & 0 deletions Sources/eudiWalletOidcIos/Service/CredentialRevocationUtil.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//
// File.swift
//
//
// Created by iGrant on 02/12/24.
//

import Foundation
import Compression
import zlib

public class CredentialRevocationUtil {

public init() {}

public func getRevokedCredentials(credentialList: [String]) async -> [String]{
var revokedCredentials: [String] = []
var statusList: [String] = []
for item in credentialList {
if let statusUri = getStatusDetailsFromStatusList(jwt: item).0 {
statusList.append(statusUri)
}
}
let uiniqueStatusListArray = Array(Set(statusList))
let statusModelList = await fetchStatusModel(statusList: uiniqueStatusListArray)
for item in credentialList {
let statusIndex = getStatusDetailsFromStatusList(jwt: item).1 ?? 0
let statusUri = getStatusDetailsFromStatusList(jwt: item).0
for data in statusModelList {
if statusUri == data.satausUri {
let statusList = data.bitsArray?[statusIndex]
if statusList == 1 {
revokedCredentials.append(item)
}
}
}
}
return revokedCredentials
}

func getStatusDetailsFromStatusList(jwt: String?) -> (String?, Int?) {
guard let split = jwt?.split(separator: "."), split.count > 1 else { return (nil, nil)}
let jsonString = "\(split[1])".decodeBase64() ?? ""
let dict = UIApplicationUtils.shared.convertStringToDictionary(text: jsonString)
guard let statusData = dict?["status"] as? [String: Any] else { return (nil, nil) }
if let statusListDict = statusData["status_list"] as? [String: Any], let statusIndex = statusListDict["idx"] as? Int , let statusUri = statusListDict["uri"] as? String {
return (statusUri, statusIndex)
}
return (nil, nil)
}

func fetchStatusModel(statusList: [String]) async -> [StatusListModel]{
var statusModel: [StatusListModel] = []
for uri in statusList {
var request = URLRequest(url: URL(string: uri)!)
request.httpMethod = "GET"
request.setValue("application/statuslist+jwt", forHTTPHeaderField: "Accept")
do {
let (data, _) = try await URLSession.shared.data(for: request)
let stringData = String.init(data: data, encoding: .utf8)
let split = stringData?.split(separator: ".")
let jsonString = "\(split?[1] ?? "")".decodeBase64() ?? ""
let statusDict = UIApplicationUtils.shared.convertStringToDictionary(text: jsonString)
let statusListDict = statusDict?["status_list"] as? [String: Any]
let bits = statusListDict?["bits"] as? Int
let lst = statusListDict?["lst"] as? String ?? ""
let statusList = StatusList.fromEncoded(lst, bits: bits ?? 0)
let bitsArray = statusList.decodedValues()
let statusValues = StatusListModel(satausUri: uri, bitsArray: bitsArray)
statusModel.append(statusValues)
} catch {
print("error")
}
}
return statusModel
}

}

struct StatusListModel {
let satausUri: String?
let bitsArray: [Int]?
}
87 changes: 87 additions & 0 deletions Sources/eudiWalletOidcIos/Service/StatusList.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import Foundation
import zlib

class StatusList {
private var list: [UInt8]
private let bits: Int
private let divisor: Int
var size: Int

init(size: Int, bits: Int) {
self.size = size
self.bits = bits
self.divisor = 8 / bits
self.list = Array(repeating: 0, count: size / divisor)
}

static func fromEncoded(_ encoded: String, bits: Int = 1) -> StatusList {
let newInstance = StatusList(size: 0, bits: bits)
newInstance.decode(encoded)
return newInstance
}

func decode(_ input: String) {
let paddedInput = input.padding(toLength: ((input.count + 3) / 4) * 4, withPad: "=", startingAt: 0)
let base64 = paddedInput
.replacingOccurrences(of: "-", with: "+")
.replacingOccurrences(of: "_", with: "/")
guard let decodedData = Data(base64Encoded: base64) else {
fatalError("Invalid Base64 string.")
}
guard let decompressedData = decompress(data: decodedData) else {
fatalError("Decompression failed.")
}
self.list = Array(decompressedData) // Update the list with decompressed data
self.size = self.list.count * divisor // Update the size based on decompressed data
print("Decoded list size: \(self.size)") // Debug: Check the size
}

func get(_ pos: Int) -> Int {
let rest = pos % divisor
let floored = pos / divisor
let shift = rest * bits
let mask = ((1 << bits) - 1) << shift
return Int((list[floored] & UInt8(mask)) >> shift)
}

func decodedValues() -> [Int] {
var values = [Int]()
for pos in 0..<size {
values.append(get(pos))
}
return values
}

private func decompress(data: Data) -> Data? {
var decompressed = Data()
var stream = z_stream()
stream.next_in = UnsafeMutablePointer<UInt8>(mutating: (data as NSData).bytes.bindMemory(to: UInt8.self, capacity: data.count))
stream.avail_in = uint(data.count)

guard inflateInit_(&stream, ZLIB_VERSION, Int32(MemoryLayout<z_stream>.size)) == Z_OK else { return nil }

let bufferSize = 4096
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
defer { buffer.deallocate() }

repeat {
stream.next_out = buffer
stream.avail_out = uint(bufferSize)

let status = inflate(&stream, Z_NO_FLUSH)
if status == Z_STREAM_END {
decompressed.append(buffer, count: bufferSize - Int(stream.avail_out))
break
} else if status != Z_OK {
inflateEnd(&stream)
return nil
}

decompressed.append(buffer, count: bufferSize - Int(stream.avail_out))
} while stream.avail_out == 0

inflateEnd(&stream)
return decompressed
}

}

0 comments on commit 63d8696

Please sign in to comment.