From fc1c992cdee8b55bcbeaa61a24d3a16a67e5b4b0 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Wed, 15 May 2024 11:52:40 -0700 Subject: [PATCH 1/8] fix: [Snyk] Security upgrade devise_token_auth from 1.2.1 to 1.2.3 (#9468) fix: Gemfile & Gemfile.lock to reduce vulnerabilities The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-RUBY-ACTIONCABLE-20338 - https://snyk.io/vuln/SNYK-RUBY-RACK-1061917 Co-authored-by: snyk-bot --- Gemfile | 2 +- Gemfile.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Gemfile b/Gemfile index 9241cc253..bee9eddc1 100644 --- a/Gemfile +++ b/Gemfile @@ -71,7 +71,7 @@ gem 'barnes' ##--- gems for authentication & authorization ---## gem 'devise', '>= 4.9.4' gem 'devise-secure_password', git: 'https://github.com/chatwoot/devise-secure_password', branch: 'chatwoot' -gem 'devise_token_auth' +gem 'devise_token_auth', '>= 1.2.3' # authorization gem 'jwt' gem 'pundit' diff --git a/Gemfile.lock b/Gemfile.lock index 2aa13fea9..2f890deaa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -200,10 +200,10 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) - devise_token_auth (1.2.1) + devise_token_auth (1.2.3) bcrypt (~> 3.0) devise (> 3.5.2, < 5) - rails (>= 4.2.0, < 7.1) + rails (>= 4.2.0, < 7.2) diff-lcs (1.5.0) digest-crc (0.6.4) rake (>= 12.0.0, < 14.0.0) @@ -474,7 +474,7 @@ GEM uri net-http-persistent (4.0.2) connection_pool (~> 2.2) - net-imap (0.4.10) + net-imap (0.4.11) date net-protocol net-pop (0.1.2) @@ -489,7 +489,7 @@ GEM sidekiq newrelic_rpm (9.6.0) base64 - nio4r (2.7.1) + nio4r (2.7.3) nokogiri (1.16.5) mini_portile2 (~> 2.8.2) racc (~> 1.4) @@ -819,7 +819,7 @@ GEM working_hours (1.4.1) activesupport (>= 3.2) tzinfo - zeitwerk (2.6.13) + zeitwerk (2.6.14) PLATFORMS arm64-darwin-20 @@ -860,7 +860,7 @@ DEPENDENCIES debug (~> 1.8) devise (>= 4.9.4) devise-secure_password! - devise_token_auth + devise_token_auth (>= 1.2.3) dotenv-rails down elastic-apm From 7ed375f6f55b259d8242117ce728365259c24b87 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Wed, 15 May 2024 15:53:41 -0700 Subject: [PATCH 2/8] chore: Show valid error messages on Inbox creation (#9474) At the moment, when creating an inbox for Whatsapp, Telegram, etc., we show a generic error message saying that inbox creation failed. This PR will show the error messages directly from the API call, which is more helpful as it says if the error is due to the provided credentials. --- .../dashboard/settings/inbox/channels/360DialogWhatsapp.vue | 4 +++- .../dashboard/settings/inbox/channels/CloudWhatsapp.vue | 4 +++- .../routes/dashboard/settings/inbox/channels/Telegram.vue | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/360DialogWhatsapp.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/360DialogWhatsapp.vue index ded9142db..ebac2a2d1 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/360DialogWhatsapp.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/360DialogWhatsapp.vue @@ -111,7 +111,9 @@ export default { }, }); } catch (error) { - this.showAlert(this.$t('INBOX_MGMT.ADD.WHATSAPP.API.ERROR_MESSAGE')); + this.showAlert( + error.message || this.$t('INBOX_MGMT.ADD.WHATSAPP.API.ERROR_MESSAGE') + ); } }, }, diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/CloudWhatsapp.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/CloudWhatsapp.vue index a6253e516..dd320dd17 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/CloudWhatsapp.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/CloudWhatsapp.vue @@ -155,7 +155,9 @@ export default { }, }); } catch (error) { - this.showAlert(this.$t('INBOX_MGMT.ADD.WHATSAPP.API.ERROR_MESSAGE')); + this.showAlert( + error.message || this.$t('INBOX_MGMT.ADD.WHATSAPP.API.ERROR_MESSAGE') + ); } }, }, diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Telegram.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Telegram.vue index 1f677bd66..c7cbaeb4a 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Telegram.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Telegram.vue @@ -86,7 +86,8 @@ export default { }); } catch (error) { this.showAlert( - this.$t('INBOX_MGMT.ADD.TELEGRAM_CHANNEL.API.ERROR_MESSAGE') + error.message || + this.$t('INBOX_MGMT.ADD.TELEGRAM_CHANNEL.API.ERROR_MESSAGE') ); } }, From 8520846b91aaf3ecca048f31d47754625c1f89b7 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Wed, 15 May 2024 16:10:39 -0700 Subject: [PATCH 3/8] chore: Improved indexes for Conversations & Contacts [CW-3300] (#9475) Based on our recent performant optimisation exercises, We have identified a better indexing strategy for conversations and contacts. The previous index on last_activity_at for conversations significantly slowed down conversation filters. Similarly, the new index on Contacts will allow the page rendering to improve for accounts with many contacts. fixes: https://linear.app/chatwoot/issue/CW-3300/db-improvements --- app/models/contact.rb | 1 + app/models/conversation.rb | 1 - ...01632_index_improvements_conversations_contacts.rb | 11 +++++++++++ db/schema.rb | 4 ++-- 4 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20240515201632_index_improvements_conversations_contacts.rb diff --git a/app/models/contact.rb b/app/models/contact.rb index 95ee69c75..c79dd3e9e 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -25,6 +25,7 @@ # Indexes # # index_contacts_on_account_id (account_id) +# index_contacts_on_account_id_and_last_activity_at (account_id,last_activity_at DESC NULLS LAST) # index_contacts_on_blocked (blocked) # index_contacts_on_lower_email_account_id (lower((email)::text), account_id) # index_contacts_on_name_email_phone_number_identifier (name,email,phone_number,identifier) USING gin diff --git a/app/models/conversation.rb b/app/models/conversation.rb index 64412b289..3a39b82fc 100644 --- a/app/models/conversation.rb +++ b/app/models/conversation.rb @@ -41,7 +41,6 @@ # index_conversations_on_first_reply_created_at (first_reply_created_at) # index_conversations_on_id_and_account_id (account_id,id) # index_conversations_on_inbox_id (inbox_id) -# index_conversations_on_last_activity_at (last_activity_at) # index_conversations_on_priority (priority) # index_conversations_on_status_and_account_id (status,account_id) # index_conversations_on_status_and_priority (status,priority) diff --git a/db/migrate/20240515201632_index_improvements_conversations_contacts.rb b/db/migrate/20240515201632_index_improvements_conversations_contacts.rb new file mode 100644 index 000000000..f6ed8596e --- /dev/null +++ b/db/migrate/20240515201632_index_improvements_conversations_contacts.rb @@ -0,0 +1,11 @@ +class IndexImprovementsConversationsContacts < ActiveRecord::Migration[7.0] + disable_ddl_transaction! + + def change + remove_index :conversations, :last_activity_at + add_index :contacts, [:account_id, :last_activity_at], + order: { last_activity_at: 'DESC NULLS LAST' }, + algorithm: :concurrently, + name: 'index_contacts_on_account_id_and_last_activity_at' + end +end diff --git a/db/schema.rb b/db/schema.rb index 1282c6e5e..496d2e280 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_04_15_210313) do +ActiveRecord::Schema[7.0].define(version: 2024_05_15_201632) do # These are extensions that must be enabled in order to support this database enable_extension "pg_stat_statements" enable_extension "pg_trgm" @@ -426,6 +426,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_04_15_210313) do t.boolean "blocked", default: false, null: false t.index "lower((email)::text), account_id", name: "index_contacts_on_lower_email_account_id" t.index ["account_id", "email", "phone_number", "identifier"], name: "index_contacts_on_nonempty_fields", where: "(((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))" + t.index ["account_id", "last_activity_at"], name: "index_contacts_on_account_id_and_last_activity_at", order: { last_activity_at: "DESC NULLS LAST" } t.index ["account_id"], name: "index_contacts_on_account_id" t.index ["account_id"], name: "index_resolved_contact_account_id", where: "(((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))" t.index ["blocked"], name: "index_contacts_on_blocked" @@ -483,7 +484,6 @@ ActiveRecord::Schema[7.0].define(version: 2024_04_15_210313) do t.index ["contact_inbox_id"], name: "index_conversations_on_contact_inbox_id" t.index ["first_reply_created_at"], name: "index_conversations_on_first_reply_created_at" t.index ["inbox_id"], name: "index_conversations_on_inbox_id" - t.index ["last_activity_at"], name: "index_conversations_on_last_activity_at" t.index ["priority"], name: "index_conversations_on_priority" t.index ["status", "account_id"], name: "index_conversations_on_status_and_account_id" t.index ["status", "priority"], name: "index_conversations_on_status_and_priority" From ae5ef73e915a5bf969112ec9bc22c1fad0ae7bb8 Mon Sep 17 00:00:00 2001 From: Pranav Date: Wed, 15 May 2024 17:53:45 -0700 Subject: [PATCH 4/8] fix: Update the voice note format to MP3 to fix the delivery issues (#9448) Use MP3 as the default format to send voice notes recorded from Chatwoot. This change was made to fix the issue of Telegram voice notes not working with the error `WEBPAGE_CURL_FAILED` . Telegram treats the mp3 recordings as audio attachments. Once we can identify a fix for the original issue, we will revisit the `ogg` implementation. --------- Co-authored-by: Sojan Jose --- .../widgets/WootWriter/AudioRecorder.vue | 37 ++++++++++++------- .../widgets/conversation/ReplyBox.vue | 8 +++- app/javascript/shared/constants/messages.js | 1 + 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue b/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue index 132408dc2..aa566fd4d 100644 --- a/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue +++ b/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue @@ -33,6 +33,21 @@ import { convertWavToMp3 } from './utils/mp3ConversionUtils'; WaveSurfer.microphone = MicrophonePlugin; +const RECORDER_CONFIG = { + [AUDIO_FORMATS.WAV]: { + audioMimeType: 'audio/wav', + audioWorkerURL: waveWorker, + }, + [AUDIO_FORMATS.MP3]: { + audioMimeType: 'audio/wav', + audioWorkerURL: waveWorker, + }, + [AUDIO_FORMATS.OGG]: { + audioMimeType: 'audio/ogg', + audioWorkerURL: encoderWorker, + }, +}; + export default { name: 'WootAudioRecorder', mixins: [alertMixin], @@ -94,14 +109,7 @@ export default { audioSampleRate: 48000, audioBitRate: 128, audioEngine: 'opus-recorder', - ...(this.audioRecordFormat === AUDIO_FORMATS.WAV && { - audioMimeType: 'audio/wav', - audioWorkerURL: waveWorker, - }), - ...(this.audioRecordFormat === AUDIO_FORMATS.OGG && { - audioMimeType: 'audio/ogg', - audioWorkerURL: encoderWorker, - }), + ...RECORDER_CONFIG[this.audioRecordFormat], }, }, }, @@ -139,7 +147,11 @@ export default { methods: { deviceReady() { if (this.player.record().engine instanceof OpusRecorderEngine) { - if (this.audioRecordFormat === AUDIO_FORMATS.WAV) { + if ( + [AUDIO_FORMATS.WAV, AUDIO_FORMATS.MP3].includes( + this.audioRecordFormat + ) + ) { this.player.record().engine.audioType = 'audio/wav'; } } @@ -154,13 +166,12 @@ export default { async finishRecord() { let recordedContent = this.player.recordedData; let fileName = this.player.recordedData.name; - if (this.isAWhatsAppChannel) { + let type = this.player.recordedData.type; + if (this.audioRecordFormat === AUDIO_FORMATS.MP3) { recordedContent = await convertWavToMp3(this.player.recordedData); fileName = `${getUuid()}.mp3`; + type = AUDIO_FORMATS.MP3; } - const type = !this.isAWhatsAppChannel - ? this.player.recordedData.type - : 'audio/mp3'; const file = new File([recordedContent], fileName, { type }); this.fireRecorderBlob(file); }, diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue index 83d31d11f..42fa74ec7 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue @@ -53,7 +53,6 @@ v-if="showAudioRecorderEditor" ref="audioRecorderInput" :audio-record-format="audioRecordFormat" - :is-a-whats-app-channel="isAWhatsAppChannel" @state-recorder-progress-changed="onStateProgressRecorderChanged" @state-recorder-changed="onStateRecorderChanged" @finish-record="onFinishRecorder" @@ -502,7 +501,10 @@ export default { return `draft-${this.conversationIdByRoute}-${this.replyType}`; }, audioRecordFormat() { - if (this.isAPIInbox || this.isATelegramChannel) { + if (this.isAWhatsAppChannel || this.isATelegramChannel) { + return AUDIO_FORMATS.MP3; + } + if (this.isAPIInbox) { return AUDIO_FORMATS.OGG; } return AUDIO_FORMATS.WAV; @@ -1250,6 +1252,7 @@ export default { } } } + .send-button { @apply mb-0; } @@ -1274,6 +1277,7 @@ export default { .emoji-dialog--rtl { @apply left-[unset] -right-80; + &::before { transform: rotate(90deg); filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.08)); diff --git a/app/javascript/shared/constants/messages.js b/app/javascript/shared/constants/messages.js index b3ef11e1b..9451f83d3 100644 --- a/app/javascript/shared/constants/messages.js +++ b/app/javascript/shared/constants/messages.js @@ -98,6 +98,7 @@ export const CSAT_RATINGS = [ export const AUDIO_FORMATS = { WEBM: 'audio/webm', OGG: 'audio/ogg', + MP3: 'audio/mp3', WAV: 'audio/wav', }; From 565747357321bf6b1a9156f4ace458b0071d602d Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Thu, 16 May 2024 09:16:02 +0530 Subject: [PATCH 5/8] fix: Dashboard phone number input country `undefined` in `onSelectCountry` (#9473) # Pull Request Template ## Description This PR will fix this sentry [issue](https://chatwoot-p3.sentry.io/issues/5291039795/) **Issue** The root cause of this issue is the usage of `keyboardEventListenerMixins`. The key events are always active when the edit conversation modal is active, even if the country dropdown is not visible. So, if we press the enter key, this error will be thrown into the console. **Solution** Remove the use of `keyboardEventListenerMixins` and handle it directly in the Vue native key events. Also, always check if the dropdown is active. **Other changes** 1. Remove the `mouseup` event lister and use the click away directive. 2. Use inline Tailwind css Fixes https://linear.app/chatwoot/issue/CW-3282/phonenumberinput-country-undefined-in-onselectcountry ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? **Steps** 1. Open a conversation. 3. And click the edit contact button 4. And click the enter key 5. Now you can see the error in the console ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --- .../components/widgets/forms/PhoneInput.vue | 176 ++++++------------ 1 file changed, 62 insertions(+), 114 deletions(-) diff --git a/app/javascript/dashboard/components/widgets/forms/PhoneInput.vue b/app/javascript/dashboard/components/widgets/forms/PhoneInput.vue index 9b77faafe..6b09acbac 100644 --- a/app/javascript/dashboard/components/widgets/forms/PhoneInput.vue +++ b/app/javascript/dashboard/components/widgets/forms/PhoneInput.vue @@ -1,9 +1,16 @@