Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What would be the most elegant way to decrypt image data before it is sent to the pipeline? #794

Open
tkrajacic opened this issue Jun 28, 2024 · 4 comments
Labels

Comments

@tkrajacic
Copy link

Suppose I have images that are encrypted on the server and whenever I fetch them I have a key (per image) that I need to decrypt the Data with.

I could basically copy all of the regular DataLoader implementation, pass the key as fragment in the image URL, so it will never be sent, but the loader could then use it from the request to decode the Data. This seems doable but requires copying most of the implementation of the URLSession based loading.

It would be nicer if there was a way to just intercept the data in the pipeline. Maybe there is and I just haven't found it. Image processors would be in the right place of the pipeline I think, but they already assume valid image data iiuc.

Ideally I think I want to create an image request that I can use in SwiftUI like

LazyImage(request: .decryptingRequest(for: urlRequest, key: key))
@kean
Copy link
Owner

kean commented Jun 29, 2024

The decoding happens using ImageDecoding objects. I suggest adding the decryption step during that stage, and then invoking the built-in decoders. See https://kean-docs.github.io/nuke/documentation/nuke/image-decoding for more information.

@kean kean added the question label Jun 29, 2024
@tkrajacic
Copy link
Author

tkrajacic commented Jul 2, 2024

Ah, that sounds promising!

Thanks for making such a great library. It is amazing!

Edit: I can use the userInfo dictionary for the key I suppose!

ImagePipeline.shared = ImagePipeline {
   $0.makeImageDecoder = { context in
      if let key = context.request.userInfo["key"] as? Data {
         var copy = context
         copy.data = try! decrypt(data: context.data, using: key)
         return ImageDecoderRegistry.shared.decoder(for: copy)
      }
      return ImageDecoderRegistry.shared.decoder(for: context)
   }
}

When creating the image pipeline, I set the makeImageDecoder closure to check for a given key and then decode the data. The data is properly decoded, but the image state says Failed to decode image data using decoder Nuke.ImageDecoders.Default even though I can check with the debugger that the default decoder can in fact decode the image.

@kean
Copy link
Owner

kean commented Jul 7, 2024

Failed to decode image data using decoder Nuke.ImageDecoders.Default even though I can check with the debugger that the default decoder can in fact decode the image.

The code that you provided looks good.

Btw, makeImageDecoder is called on the pipeline's background queue, so I think it's an OK trade-off performance-wise to put it there.

@tkrajacic
Copy link
Author

Sorry for the very late responses here.

So It seems Nuke doesn't get me the correct decoder with my code. If I add a debug line (the one after the comment)

$0.makeImageDecoder = { context in
    if let key = context.request.userInfo["key"] as? Data {
        var copy = context
        copy.data = try! Cryptor.default.decrypt(data: context.data, using: .init(data: key))
        // this gets me to the correct image…
        let image = try! Nuke.ImageDecoders.Default().decode(copy.data)
        return ImageDecoderRegistry.shared.decoder(for: copy)
    }
    return ImageDecoderRegistry.shared.decoder(for: context)
}

then I can see that the image is correctly decoded. returning the ImageDecoderRegistry.shared.decoder(for: copy) though doesn't seem to work (although the error message that I receive
Failed to decode image data using decoder Nuke.ImageDecoders.Default
seems to indicate it wants to pick the right one anyway.

Do you have any suggestions of where I should be looking?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants