GetStream / stream-chat-react

React Chat SDK ➜ Stream Chat 💬
https://getstream.io/chat/sdk/react/
Other
702 stars 274 forks source link

bug: UploadImage failed with error: "File type application/octet-stream is not supported" for encrypted file #1908

Closed thecannabisapp closed 1 year ago

thecannabisapp commented 1 year ago

Describe the bug

Can someone help me, please? I am trying to use Virgil e3kit to encrypt and then upload an image to the default stream CDN using a custom image upload handler through doImageUploadRequest on the MessageInput component.

When I try to upload a file, I get an error from the API response UploadImage failed with error: "File type application/octet-stream is not supported"

Screenshot 2023-01-14 at 21 09 08

Is it possible to encrypt and upload to the stream CDN this way?

Here's the code for my Channel Component, where I have implemented the custom upload handler.

import { Channel, SendFileAPIResponse } from "stream-chat";
import {
  ImageUpload,
  MessageInput,
  MessageList,
  MessageToSend,
  Window,
  useChannelActionContext,
  useChannelStateContext,
} from "stream-chat-react";
import { useUserContext } from "../../contexts/UserProvider";
import useEncryption from "../../hooks/useEncryption";
import MessageEncrypted from "./MessageEncrypted";

type TEncryptedMedia = {
  encrypted: string | Buffer;
  file: File | Blob;
  fileKey: Buffer;
};

const isEncryptedFileResponse = (
  encryptedMedia: string | Buffer | TEncryptedMedia | undefined
): encryptedMedia is TEncryptedMedia => {
  return !!encryptedMedia?.hasOwnProperty("fileKey");
};

export const ChannelContent = () => {
  const { user } = useUserContext();
  const { members, channel } = useChannelStateContext();
  const { sendMessage } = useChannelActionContext();
  const { encrypt } = useEncryption();

  if (!members || !channel) return <></>;

  const handleImageUpload = async (
    file: ImageUpload["file"],
    channel: Channel
  ): Promise<SendFileAPIResponse> => {
    const encryptedMedia = await encrypt(channel, "", file as File);
    if (!isEncryptedFileResponse(encryptedMedia)) {
      throw new Error("encryptedMedia data is not encrypted media response");
    }
    const sendImage = await channel.sendImage(
      encryptedMedia.file as File,
      encryptedMedia.file.name,
      encryptedMedia.file.type
    );
    return sendImage;
  };

  return (
    <Window>
      <MessageList Message={MessageEncrypted} />
      <MessageInput
        doImageUploadRequest={handleImageUpload}
      />
    </Window>
  );
};

This is my encrypt function.

  const encrypt = async (
    c: Channel<DefaultStreamChatGenerics>,
    message: string,
    file?: File
  ) => {
    try {
      await loadGroup(c);
      const group = getGroup(c);
      const encrypted = await group.encrypt(message);
      if (file) {
        const e = getEncryption();
        const { encryptedSharedFile, fileKey } = await e.encryptSharedFile(
          file
        );
        const groupFileKey = await group.encrypt(fileKey);

        return {
          encrypted,
          file: encryptedSharedFile,
          fileKey: groupFileKey as Buffer,
        };
      }
      return encrypted;
    } catch (error) {
      console.debug(error);
    }
  };

Package version

thecannabisapp commented 1 year ago

I'm closing the issue as I'm receiving help from support via email.