opsdroid icon indicating copy to clipboard operation
opsdroid copied to clipboard

Attachments in encrypted rooms are not automatically decrypted

Open manueldavid123 opened this issue 2 years ago • 4 comments

Description

When I try to read a file uploaded to a private room, the byte representation appears encrypted. However, when I run it on a public room, I don't have that problem and I can read the file without problems.

Steps to Reproduce

Upload a txt file with any content (in this case, only one line with the text 'hola') to a private room. A skill with match_event(File) decorator will receive the event. When the method "get_file_bytes()" is called, it returns the content encrypted

Expected Functionality

The method get_file_bytes() should return the bytes representation of the file.

This method should return the data b'hola'

Experienced Functionality

The method get_file_bytes() returns the bytes representation of the file encrypted.

This method returns b'\xc6p\xa09'

Versions

  • Opsdroid version: 0.28.0
  • Python version: 3.9.6
  • OS/Docker version: opsdroid/opsdroid:latest

Configuration File

Please include your version of the configuration file below.

connectors:
  matrix:
    # Required
    mxid: "user"
    password: "pass"
    rooms:
      'main': 'room'
    homeserver: "https://matrix.org"
    enable_encryption: True
    device_id: "device"
    store_path: /home/opsdroid/.keys/
    room_specific_nicks: False

databases:
  matrix:

Example Code

    @match_event(File)
    async def file_skill(self, event):
        try:
            data_in_bytes = await event.get_file_bytes()
            filename = event.name
            user = event.raw_event['sender']
            print (str(event.__dict__))

manueldavid123 avatar Apr 27 '23 11:04 manueldavid123

After an intense search in other projects, I have found the solution to my problem.

When a file is uploaded to a private room, the content of that file is encrypted. Once downloaded, it is necessary to decrypt it using external libraries.

Here I show an example code to decrypt files from Matrix:

    @match_event(File)
    async def file_skill(self, event):
        try:
            data_in_bytes = await event.get_file_bytes()
            content = event.raw_event['content']

            if ('file' in content):
                # The file is encoded
                file_data = event.raw_event['content']['file']
                
                data_in_bytes = crypto.attachments.decrypt_attachment(
                                        data_in_bytes,
                                        file_data["key"]["k"],
                                        file_data["hashes"]["sha256"],
                                        file_data["iv"],
                                    )
            	

            return data_in_bytes.decode('utf-8')
        except BaseException as e:
        	logging.error(e)

        return None

In my opinion, this information should be added to the connectors documentation.

If anyone has any comments, fell free to post it. Otherwise, this issue can be closed.

manueldavid123 avatar Apr 28 '23 18:04 manueldavid123

Thanks for figuring this one out and providing the code to decrypt the attachment. We should definitely add this to the connector so it's transparent to the skills.

Cadair avatar May 09 '23 07:05 Cadair

Hi there, was wondering if this has been done and if not if I could be assigned to it? I am a first time contributor so I might ask a few questions about it if I get stuck. Thanks and looking forward to hearing back!

u7498708 avatar Oct 21 '23 18:10 u7498708

@Cadair just in case I needed to mention you :)

u7498708 avatar Oct 21 '23 18:10 u7498708