Skip to content

Send encrypted message (encrypt the content) #1767

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

Closed
mmeksasi opened this issue Jul 5, 2021 · 14 comments
Closed

Send encrypted message (encrypt the content) #1767

mmeksasi opened this issue Jul 5, 2021 · 14 comments

Comments

@mmeksasi
Copy link

mmeksasi commented Jul 5, 2021

I'm trying to send a message to an encrypted room but I don't know if the event should send it as encrypted if the room is encrypted the content is being sent as :

{
body: "awd"
msgtype: "m.text"
}

but it should be sent as:

{
algorithm: "m.megolm.v1.aes-sha2"
ciphertext: "AwgAEoABQOtcxhnyiDr9cxt30p/aJmRKo+X9t8Ci+RNEgL3M6LDQqTCCD7IQgN0ycaJ06kYS+UUOX/5egx5wF52ZZKwcmsLX0UnSj0V4bWMmnUJ4V6jGtwmMmSgzUhOxHZn7TJAxK8f+hc570nKFStrgjCECo3cVuJY9jef/HYmWmWCgadqVMs/ccfEzmHxeSgQr8b0W3VQFQnGzqkATgc3EKAudEGUUgwpoJNUA+DwcHNzHdliQD9YTor7TFzRGclcjYg0+fdGs9JiBQwo"
device_id: "AOYIRWXKAX"
sender_key: "wjdd/u7lzUge/eXvNuNCBKpef/BGJSYoX3kWyXL0hSo"
session_id: "1M/hp/iwSJHbxTN+4B4vyTtJ8n4Pyv6ucMypfurJkQo"
}

Maybe i need to use MegolmEncryption.encryptMessage but i didn't know how to use it if someone can help

export const sendMessageChat = async ({
  message,
  roomID,
}) => {
  const content = {
    body: message,
    msgtype: 'm.text',
  };

  try {
    const result = await matrixAlias.sendEvent(
      roomID,
      'm.room.encrypted',
      content
    );
  } catch (err) {
    console.log('SEND MESSAGE ERROR ', err);
    alert('sending error');
  }
};
@t3chguy
Copy link
Member

t3chguy commented Jul 5, 2021

Please share your full minimal example. For encryption to work you will need awaited call to initCrypto and startClient, and await the first initial sync so that the client even knows that the room is encrypted.

https://github.com/matrix-org/matrix-js-sdk#end-to-end-encryption-support

@mmeksasi
Copy link
Author

mmeksasi commented Jul 5, 2021

From element when i send a message in an encrypted room the decryptEvent is working and the message is being recieved properly on simulator so encryption should be working but when i send it from simulator i get this error on element ** Unable to decrypt: Unknown encryption algorithm "undefined". ** because the content is :
{
body: "awd"
msgtype: "m.text"
}
not
{
algorithm: "m.megolm.v1.aes-sha2"
ciphertext: "AwgAEoABQOtcxhnyiDr9cxt30p/aJmRKo+X9t8Ci+RNEgL3M6LDQqTCCD7IQgN0ycaJ06kYS+UUOX/5egx5wF52ZZKwcmsLX0UnSj0V4bWMmnUJ4V6jGtwmMmSgzUhOxHZn7TJAxK8f+hc570nKFStrgjCECo3cVuJY9jef/HYmWmWCgadqVMs/ccfEzmHxeSgQr8b0W3VQFQnGzqkATgc3EKAudEGUUgwpoJNUA+DwcHNzHdliQD9YTor7TFzRGclcjYg0+fdGs9JiBQwo"
device_id: "AOYIRWXKAX"
sender_key: "wjdd/u7lzUge/eXvNuNCBKpef/BGJSYoX3kWyXL0hSo"
session_id: "1M/hp/iwSJHbxTN+4B4vyTtJ8n4Pyv6ucMypfurJkQo"
}

I don't know if I should encrypt the message or it should be encrypted automatically when using

const content = {
body: message,
msgtype: 'm.text',
};

try {
const result = await matrixAlias.sendEvent(
roomID,
'm.room.encrypted',
content
);
} catch (err) {
console.log('SEND MESSAGE ERROR ', err);
alert('sending error');
}

P.S I'm using react native so I can't add global.Olm = require('olm'); but everything related to crypto is working also I'm using
await matrixClient.initCrypto();
await matrixClient.startClient();

@t3chguy
Copy link
Member

t3chguy commented Jul 5, 2021

and await the first initial sync so that the client even knows that the room is encrypted.

@mmeksasi
Copy link
Author

mmeksasi commented Jul 5, 2021

I'm awaiting everything, the send event if the type is m.room.encrypted it should encrypt the message content automatically or i should encrypt it before using it?

@t3chguy
Copy link
Member

t3chguy commented Jul 5, 2021

You should be using event type m.room.message - the js-sdk will wrap it inside an m.room.encrypted event's payload if it sees the room is encrypted at send time.

@t3chguy
Copy link
Member

t3chguy commented Jul 5, 2021

If you do not provide a COMPLETE functional yet minimal example you cannot be helped.

@mmeksasi
Copy link
Author

mmeksasi commented Jul 5, 2021

import React, { useEffect } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import matrixSdk, { MemoryStore, MatrixEvent } from 'matrix-js-sdk';
import request from 'xmlhttp-request';
import AsyncStorage from '@react-native-async-storage/async-storage';
import AsyncCryptoStore from './lib/AsyncCryptoStore';

const BASE_URL = 'http://192.168.102.121:30808';
export const MATRIX_CLIENT_START_OPTIONS = {
  initialSyncLimit: 10,
  request: request,
  lazyLoadMembers: true,
  pendingEventOrdering: 'detached',
  timelineSupport: true,
  unstableClientRelationAggregation: true,
  store: new MemoryStore({
    localStorage: AsyncStorage,
  }),
  cryptoStore: new AsyncCryptoStore(AsyncStorage),
  sessionStore: {
    getLocalTrustedBackupPubKey: () => null,
  }, // js-sdk complains if this isn't supplied but it's only used for remembering a local trusted backup key
};
export var matrixAlias = {};

export const LoginToChat = async ({ register = false, callBack }) => {
  try {
    const username = 'dtp18';
    const chatPassword = 'Midomek@1';
    const registrationClient = await matrixSdk.createClient(BASE_URL);
    if (username && chatPassword) {
      try {
        userRegisterResult = await registrationClient.login(
          'm.login.password',
          {
            user: username,
            password: chatPassword,
          }
        );
      } catch (e) {
        console.log('error login', e);
      }
    } else {
      return;
    }

    const matrixClient = await matrixSdk.createClient({
      baseUrl: BASE_URL,
      userId: userRegisterResult.user_id,
      accessToken: userRegisterResult.access_token,
      deviceId: userRegisterResult.device_id,
      ...MATRIX_CLIENT_START_OPTIONS,
    });
    await matrixClient.initCrypto();
    await matrixClient.startClient();
    matrixAlias = matrixClient;
    matrixAlias.once('sync', async function (state, prevState, res) {
      // after client is ready
      if (state === 'PREPARED') {
        await matrixClient.uploadKeys();
        matrixClient.exportRoomKeys();
        getTimeline();
        callBack && callBack();
      }
    });
  } catch (e) {
    printError(e);
  }
};

export const sendMessageChat = async ({ message, roomID }) => {
  autoVerify(roomID);

  const content = {
    body: message,
    msgtype: 'm.text',
  };

  try {
    const result = await matrixAlias.sendEvent(
      roomID,
      'm.room.message',
      content
    );
  } catch (err) {
    console.log('SEND MESSAGE ERROR ', err);
    alert('sending error');
  }
};

export const getTimeline = () => {
  matrixAlias.on('Room.timeline', async (message, room, toStartOfTimeline) => {
    let body = '';
    let event;

    try {
      if (message.event.type === 'm.room.encrypted') {
        autoVerify(message.event.room_id);

        event = await matrixAlias._crypto.decryptEvent(message);
        ({ body } = event?.clearEvent?.content ?? '');
      } else {
        ({ body } = message.event.content);
      }

      if (body) {
        console.log(body);
      }
    } catch (error) {
      console.error('RECEIVE MESSAGE ERROR ', error);
    }
  });
};

export const autoVerify = async (room_id) => {
  let room = matrixAlias.getRoom(room_id);
  const e2eMembers = await room.getEncryptionTargetMembers();
  for (const member of e2eMembers) {
    const devices = matrixAlias.getStoredDevicesForUser(member.userId);
    for (const device of devices) {
      if (device.isUnverified()) {
        await verifyDevice(member.userId, device.deviceId);
      }
    }
  }
};

export async function verifyDevice(userId, deviceId) {
  if (!userId || typeof userId !== 'string') {
    throw new Error('"userId" is required and must be a string.');
  }
  if (!deviceId || typeof deviceId !== 'string') {
    throw new Error('"deviceId" is required and must be a string.');
  }
  await matrixAlias.setDeviceKnown(userId, deviceId, true);
  await matrixAlias.setDeviceVerified(userId, deviceId, true);
}

const testingChat = () => {
  useEffect(() => {
    LoginToChat({
      callBack: () => {
        sendMessageChat({
          message: 'hello',
          roomID: '!NrNMsmxdVaSDSnhzYc:kubernetesMaster.dtp.ae',
        });
      },
    });
  }, []);
  return  null
};

export default testingChat;

@t3chguy
Copy link
Member

t3chguy commented Jul 5, 2021

I don't see you awaiting the initial sync in there

and await the first initial sync so that the client even knows that the room is encrypted.

sendMessageChat is also never called so you are clearly not sharing a complete example.

@mmeksasi
Copy link
Author

mmeksasi commented Jul 5, 2021

Check the example now please and really thank you for your time, if it's not sufficient tomorrow i will try to make a better example

@mmeksasi mmeksasi closed this as completed Jul 5, 2021
@mmeksasi mmeksasi reopened this Jul 5, 2021
@mmeksasi
Copy link
Author

mmeksasi commented Jul 6, 2021

turned out if i send a message from another device the message in timeline will be encrypted but when i send the message from the same device and see it in the timeline the event content will not be encrypted

@mmeksasi mmeksasi closed this as completed Jul 6, 2021
@t3chguy
Copy link
Member

t3chguy commented Jul 6, 2021

Ah, so yes getContent() will try get the decrypted content, you can use getWireContent() to see the actual content in the event

@ppulwey
Copy link

ppulwey commented Jul 19, 2021

@mmeksasi Thanks for sharing the code. Helped me a lot! Now I can't find you loading of the Olm library. RN is complaining about this error on init [Error: End-to-end encryption not supported in this js-sdk build: did you remember to load the olm library?]

I've downloaded from here and run a build. I use the legacy version as the version with webassebly seems not to run in RN. Looking for 2 days now into that but I can't manage to run the project.

How did you solved this?

@Electrofenster
Copy link

I've got it working by using:

import Olm from 'olm/olm_legacy';
global.Olm = Olm;

using this in my package.json
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",

@ppulwey
Copy link

ppulwey commented Aug 26, 2021

See my sample repo for reference sample repo here

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

No branches or pull requests

4 participants