mirror of
https://github.com/Safe-Support-Chat/ocrcc-chatbox
synced 2024-11-01 00:55:26 +00:00
fallback to unencryted chat if initCrypto fails or on decryption error
This commit is contained in:
parent
b934bb3a5f
commit
5569c4af63
@ -24,12 +24,16 @@ const DEFAULT_ROOM_NAME = "Support Chat"
|
|||||||
const BOT_USERNAME = "@help-bot:rhok.space"
|
const BOT_USERNAME = "@help-bot:rhok.space"
|
||||||
const ENCRYPTION_CONFIG = { "algorithm": "m.megolm.v1.aes-sha2" };
|
const ENCRYPTION_CONFIG = { "algorithm": "m.megolm.v1.aes-sha2" };
|
||||||
const ENCRYPTION_NOTICE = "Messages in this chat are secured with end-to-end encryption."
|
const ENCRYPTION_NOTICE = "Messages in this chat are secured with end-to-end encryption."
|
||||||
|
const UNENCRYPTION_NOTICE = "End-to-end message encryption is not available on this browser."
|
||||||
const INTRO_MESSAGE = "This chat application does not collect any of your personal data or any data from your use of this service."
|
const INTRO_MESSAGE = "This chat application does not collect any of your personal data or any data from your use of this service."
|
||||||
const AGREEMENT_MESSAGE = "👉 Do you want to continue? Type yes or no."
|
const AGREEMENT_MESSAGE = "👉 Do you want to continue? Type yes or no."
|
||||||
const CONFIRMATION_MESSAGE = "Waiting for a facilitator to join the chat..."
|
const CONFIRMATION_MESSAGE = "Waiting for a facilitator to join the chat..."
|
||||||
|
const RESTARTING_UNENCRYPTED_CHAT_MESSAGE = "Restarting chat without encryption."
|
||||||
const EXIT_MESSAGE = "The chat was not started."
|
const EXIT_MESSAGE = "The chat was not started."
|
||||||
const FACILITATOR_ROOM_ID = '!pYVVPyFKacZeKZbWyz:rhok.space'
|
const FACILITATOR_ROOM_ID = '!pYVVPyFKacZeKZbWyz:rhok.space'
|
||||||
const TERMS_URL="https://tosdr.org/"
|
const TERMS_URL="https://tosdr.org/"
|
||||||
|
const SUPPORT_SEEKER_DISPLAY_NAME="Anonymous"
|
||||||
|
const MATRIX_ERROR_MESSAGE = "There was an error in the messaging service. Please try again later."
|
||||||
|
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
@ -172,6 +176,8 @@ class ChatBox extends React.Component {
|
|||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
localStorage: localStorage,
|
localStorage: localStorage,
|
||||||
|
sessionId: sessionId,
|
||||||
|
deviceId: data.device_id,
|
||||||
})
|
})
|
||||||
|
|
||||||
// create new client with full options
|
// create new client with full options
|
||||||
@ -184,7 +190,7 @@ class ChatBox extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client = matrix.createClient(opts)
|
client = matrix.createClient(opts)
|
||||||
client.setDisplayName("Anonymous")
|
client.setDisplayName(SUPPORT_SEEKER_DISPLAY_NAME)
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log("Registration error", err)
|
console.log("Registration error", err)
|
||||||
@ -196,9 +202,40 @@ class ChatBox extends React.Component {
|
|||||||
client: client
|
client: client
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
.catch(err => this.initializeUnencryptedChat())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initializeUnencryptedChat = () => {
|
||||||
|
this.setState({ ready: false })
|
||||||
|
|
||||||
|
let opts = {
|
||||||
|
baseUrl: this.props.matrixServerUrl,
|
||||||
|
accessToken: this.state.accessToken,
|
||||||
|
userId: this.state.userId,
|
||||||
|
deviceId: this.state.deviceId
|
||||||
|
}
|
||||||
|
|
||||||
|
let client = matrix.createClient(opts)
|
||||||
|
client.setDisplayName(SUPPORT_SEEKER_DISPLAY_NAME)
|
||||||
|
return client.startClient()
|
||||||
|
.then(() => {
|
||||||
|
this.setState({
|
||||||
|
client: client,
|
||||||
|
isCryptoEnabled: false,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDecryptionError = () => {
|
||||||
|
this.displayBotMessage({ body: RESTARTING_UNENCRYPTED_CHAT_MESSAGE })
|
||||||
|
|
||||||
|
this.state.client.leave(this.state.roomId)
|
||||||
|
.then(() => this.state.client.stopClient())
|
||||||
|
.then(() => this.state.client.clearStores())
|
||||||
|
.then(() => this.initializeUnencryptedChat())
|
||||||
|
}
|
||||||
|
|
||||||
verifyAllRoomDevices = async function(roomId) {
|
verifyAllRoomDevices = async function(roomId) {
|
||||||
let room = this.state.client.getRoom(roomId);
|
let room = this.state.client.getRoom(roomId);
|
||||||
let members = (await room.getEncryptionTargetMembers()).map(x => x["userId"])
|
let members = (await room.getEncryptionTargetMembers()).map(x => x["userId"])
|
||||||
@ -211,44 +248,44 @@ class ChatBox extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createRoom = () => {
|
createRoom = async function() {
|
||||||
const currentDate = new Date()
|
const currentDate = new Date()
|
||||||
const chatDate = currentDate.toLocaleDateString()
|
const chatDate = currentDate.toLocaleDateString()
|
||||||
const chatTime = currentDate.toLocaleTimeString()
|
const chatTime = currentDate.toLocaleTimeString()
|
||||||
return this.state.client.createRoom({
|
let roomConfig = {
|
||||||
room_alias_name: `private-support-chat-${uuid()}`,
|
room_alias_name: `private-support-chat-${uuid()}`,
|
||||||
invite: [BOT_USERNAME],
|
invite: [BOT_USERNAME],
|
||||||
visibility: 'private',
|
visibility: 'private',
|
||||||
name: `${chatDate} - ${this.props.roomName} - started at ${chatTime}`,
|
name: `${chatDate} - ${this.props.roomName} - started at ${chatTime}`,
|
||||||
initial_state: [
|
}
|
||||||
|
|
||||||
|
const isCryptoEnabled = await this.state.client.isCryptoEnabled()
|
||||||
|
|
||||||
|
if (isCryptoEnabled) {
|
||||||
|
roomConfig.initial_state = [
|
||||||
{
|
{
|
||||||
type: 'm.room.encryption',
|
type: 'm.room.encryption',
|
||||||
state_key: '',
|
state_key: '',
|
||||||
content: ENCRYPTION_CONFIG,
|
content: ENCRYPTION_CONFIG,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})
|
|
||||||
.then(data => {
|
|
||||||
this.verifyAllRoomDevices(data.room_id)
|
|
||||||
this.state.client.setPowerLevel(data.room_id, BOT_USERNAME, 100)
|
|
||||||
.then(() => console.log("Set bot power level to 100"))
|
|
||||||
.catch(err => console.log("Error setting bot power level", err))
|
|
||||||
|
|
||||||
const confirmationMsg = {
|
|
||||||
id: 'confirmation-msg-id',
|
|
||||||
type: 'm.room.message',
|
|
||||||
sender: BOT_USERNAME,
|
|
||||||
content: { body: CONFIRMATION_MESSAGE },
|
|
||||||
}
|
}
|
||||||
const messages = [...this.state.messages]
|
|
||||||
messages.push(confirmationMsg)
|
const { room_id } = await this.state.client.createRoom(roomConfig)
|
||||||
|
|
||||||
|
this.state.client.setPowerLevel(room_id, BOT_USERNAME, 100)
|
||||||
|
|
||||||
|
if (isCryptoEnabled) {
|
||||||
|
this.verifyAllRoomDevices(room_id)
|
||||||
|
} else {
|
||||||
|
this.displayBotMessage({ body: UNENCRYPTION_NOTICE })
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayBotMessage({ body: CONFIRMATION_MESSAGE })
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
roomId: data.room_id,
|
roomId: room_id,
|
||||||
messages
|
isCryptoEnabled
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log("Unable to create room", err)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +311,34 @@ class ChatBox extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
displayFakeMessage = (content, sender) => {
|
||||||
|
const msgList = [...this.state.messages]
|
||||||
|
const msg = {
|
||||||
|
id: uuid(),
|
||||||
|
type: 'm.room.message',
|
||||||
|
sender: sender,
|
||||||
|
roomId: this.state.roomId,
|
||||||
|
content: content,
|
||||||
|
}
|
||||||
|
msgList.push(msg)
|
||||||
|
|
||||||
|
this.setState({ messages: msgList })
|
||||||
|
}
|
||||||
|
|
||||||
|
displayBotMessage = (content, roomId) => {
|
||||||
|
const msgList = [...this.state.messages]
|
||||||
|
const msg = {
|
||||||
|
id: uuid(),
|
||||||
|
type: 'm.room.message',
|
||||||
|
sender: BOT_USERNAME,
|
||||||
|
roomId: roomId || this.state.roomId,
|
||||||
|
content: content,
|
||||||
|
}
|
||||||
|
msgList.push(msg)
|
||||||
|
|
||||||
|
this.setState({ messages: msgList })
|
||||||
|
}
|
||||||
|
|
||||||
handleMessageEvent = event => {
|
handleMessageEvent = event => {
|
||||||
const message = {
|
const message = {
|
||||||
id: event.getId(),
|
id: event.getId(),
|
||||||
@ -283,8 +348,6 @@ class ChatBox extends React.Component {
|
|||||||
content: event.getContent(),
|
content: event.getContent(),
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("INCOMING MESSAGE", message)
|
|
||||||
|
|
||||||
const messages = [...this.state.messages]
|
const messages = [...this.state.messages]
|
||||||
messages.push(message)
|
messages.push(message)
|
||||||
this.setState({ messages })
|
this.setState({ messages })
|
||||||
@ -309,35 +372,34 @@ class ChatBox extends React.Component {
|
|||||||
|
|
||||||
this.state.client.on("Room.timeline", (event, room, toStartOfTimeline) => {
|
this.state.client.on("Room.timeline", (event, room, toStartOfTimeline) => {
|
||||||
if (event.getType() === "m.room.encryption") {
|
if (event.getType() === "m.room.encryption") {
|
||||||
const msgList = [...this.state.messages]
|
this.displayBotMessage({ body: ENCRYPTION_NOTICE }, room.room_id)
|
||||||
const encryptionMsg = {
|
|
||||||
id: 'encryption-msg-id',
|
|
||||||
type: 'm.room.message',
|
|
||||||
sender: BOT_USERNAME,
|
|
||||||
roomId: room.room_id,
|
|
||||||
content: { body: ENCRYPTION_NOTICE },
|
|
||||||
}
|
}
|
||||||
msgList.push(encryptionMsg)
|
|
||||||
|
|
||||||
this.setState({ messages: msgList })
|
if (event.getType() === "m.room.message" && !this.state.isCryptoEnabled) {
|
||||||
|
if (event.isEncrypted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.handleMessageEvent(event)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.state.client.on("Event.decrypted", (event) => {
|
this.state.client.on("Event.decrypted", (event, err) => {
|
||||||
|
if (err) {
|
||||||
|
return this.handleDecryptionError()
|
||||||
|
}
|
||||||
if (event.getType() === "m.room.message") {
|
if (event.getType() === "m.room.message") {
|
||||||
this.handleMessageEvent(event)
|
this.handleMessageEvent(event)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.state.client.on("RoomMember.typing", (event, member) => {
|
this.state.client.on("RoomMember.typing", (event, member) => {
|
||||||
if (member.typing) {
|
if (member.typing && event.getRoomId() === this.state.roomId) {
|
||||||
this.setState({ typingStatus: `${member.name} is typing...`})
|
this.setState({ typingStatus: `${member.name} is typing...`})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.setState({ typingStatus: null })
|
this.setState({ typingStatus: null })
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prevState.ready && this.state.ready) {
|
if (!prevState.ready && this.state.ready) {
|
||||||
@ -374,45 +436,21 @@ class ChatBox extends React.Component {
|
|||||||
|
|
||||||
if (this.state.awaitingAgreement && !this.state.client) {
|
if (this.state.awaitingAgreement && !this.state.client) {
|
||||||
if (this.state.inputValue.toLowerCase() === 'yes') {
|
if (this.state.inputValue.toLowerCase() === 'yes') {
|
||||||
const fakeUserMsg = {
|
this.displayFakeMessage({ body: this.state.inputValue }, 'from-me')
|
||||||
id: 'fake-msg-id',
|
this.setState({ inputValue: "" })
|
||||||
type: 'm.room.message',
|
|
||||||
sender: 'from-me',
|
|
||||||
content: { body: this.state.inputValue },
|
|
||||||
}
|
|
||||||
|
|
||||||
const messages = [...this.state.messages]
|
|
||||||
messages.push(fakeUserMsg)
|
|
||||||
this.setState({ inputValue: "", messages })
|
|
||||||
|
|
||||||
return this.initializeChat()
|
return this.initializeChat()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const fakeUserMsg = {
|
this.displayFakeMessage({ body: this.state.inputValue }, 'from-me')
|
||||||
id: 'fake-msg-id',
|
this.displayBotMessage({ body: EXIT_MESSAGE })
|
||||||
type: 'm.room.message',
|
return this.setState({ inputValue: "" })
|
||||||
sender: 'from-me',
|
|
||||||
content: { body: this.state.inputValue },
|
|
||||||
}
|
|
||||||
|
|
||||||
const exitMsg = {
|
|
||||||
id: 'exit-msg-id',
|
|
||||||
type: 'm.room.message',
|
|
||||||
sender: BOT_USERNAME,
|
|
||||||
content: { body: EXIT_MESSAGE },
|
|
||||||
}
|
|
||||||
|
|
||||||
const messages = [...this.state.messages]
|
|
||||||
messages.push(fakeUserMsg)
|
|
||||||
messages.push(exitMsg)
|
|
||||||
this.setState({ inputValue: "", messages })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.client && this.state.roomId) {
|
if (this.state.client && this.state.roomId) {
|
||||||
return this.sendMessage()
|
return this.sendMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
Loading…
Reference in New Issue
Block a user