diff --git a/app/builders/messages/outgoing/normal_builder.rb b/app/builders/messages/outgoing/normal_builder.rb
index 5969a97c5..5d64608a3 100644
--- a/app/builders/messages/outgoing/normal_builder.rb
+++ b/app/builders/messages/outgoing/normal_builder.rb
@@ -22,7 +22,7 @@ class Messages::Outgoing::NormalBuilder
message_type: :outgoing,
content: @content,
private: @private,
- user_id: @user.id,
+ user_id: @user&.id,
source_id: @fb_id
}
end
diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb
index 097a40dab..d512eeabf 100644
--- a/app/controllers/api/base_controller.rb
+++ b/app/controllers/api/base_controller.rb
@@ -1,9 +1,16 @@
class Api::BaseController < ApplicationController
+ include AccessTokenAuthHelper
respond_to :json
- before_action :authenticate_user!
+ before_action :authenticate_access_token!, if: :authenticate_by_access_token?
+ before_action :validate_bot_access_token!, if: :authenticate_by_access_token?
+ before_action :authenticate_user!, unless: :authenticate_by_access_token?
private
+ def authenticate_by_access_token?
+ request.headers[:api_access_token].present?
+ end
+
def set_conversation
@conversation ||= current_account.conversations.find_by(display_id: params[:conversation_id])
end
diff --git a/app/controllers/api/v1/widget/inboxes_controller.rb b/app/controllers/api/v1/accounts/widget/inboxes_controller.rb
similarity index 93%
rename from app/controllers/api/v1/widget/inboxes_controller.rb
rename to app/controllers/api/v1/accounts/widget/inboxes_controller.rb
index ce739fef0..f6305e4eb 100644
--- a/app/controllers/api/v1/widget/inboxes_controller.rb
+++ b/app/controllers/api/v1/accounts/widget/inboxes_controller.rb
@@ -1,4 +1,4 @@
-class Api::V1::Widget::InboxesController < Api::BaseController
+class Api::V1::Accounts::Widget::InboxesController < Api::BaseController
before_action :authorize_request
before_action :set_web_widget_channel, only: [:update]
before_action :set_inbox, only: [:update]
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index f38c45c63..5bac8991e 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -14,7 +14,25 @@ class ApplicationController < ActionController::Base
private
def current_account
- @_ ||= current_user.account
+ @_ ||= find_current_account
+ end
+
+ def find_current_account
+ account = Account.find(params[:account_id])
+ if current_user
+ account_accessible_for_user?(account)
+ elsif @resource&.is_a?(AgentBot)
+ account_accessible_for_bot?(account)
+ end
+ account
+ end
+
+ def account_accessible_for_user?(account)
+ render_unauthorized('You are not authorized to access this account') unless account.account_users.find_by(user_id: current_user.id)
+ end
+
+ def account_accessible_for_bot?(account)
+ render_unauthorized('You are not authorized to access this account') unless @resource.agent_bot_inboxes.find_by(account_id: account.id)
end
def handle_with_exception
diff --git a/app/controllers/concerns/access_token_auth_helper.rb b/app/controllers/concerns/access_token_auth_helper.rb
new file mode 100644
index 000000000..9ebcf3864
--- /dev/null
+++ b/app/controllers/concerns/access_token_auth_helper.rb
@@ -0,0 +1,24 @@
+module AccessTokenAuthHelper
+ BOT_ACCESSIBLE_ENDPOINTS = {
+ 'api/v1/accounts/conversations' => ['toggle_status'],
+ 'api/v1/accounts/conversations/messages' => ['create']
+ }.freeze
+
+ def authenticate_access_token!
+ access_token = AccessToken.find_by(token: request.headers[:api_access_token])
+ render_unauthorized('Invalid Access Token') && return unless access_token
+ token_owner = access_token.owner
+ @resource = token_owner
+ end
+
+ def validate_bot_access_token!
+ return if current_user.is_a?(User)
+ return if agent_bot_accessible?
+
+ render_unauthorized('Access to this endpoint is not authorized for bots')
+ end
+
+ def agent_bot_accessible?
+ BOT_ACCESSIBLE_ENDPOINTS.fetch(params[:controller], []).include?(params[:action])
+ end
+end
diff --git a/app/javascript/dashboard/api/channel/webChannel.js b/app/javascript/dashboard/api/channel/webChannel.js
index 7fc5fb2db..5354787c3 100644
--- a/app/javascript/dashboard/api/channel/webChannel.js
+++ b/app/javascript/dashboard/api/channel/webChannel.js
@@ -2,7 +2,7 @@ import ApiClient from '../ApiClient';
class WebChannel extends ApiClient {
constructor() {
- super('widget/inboxes');
+ super('widget/inboxes', { accountScoped: true });
}
}
diff --git a/app/javascript/dashboard/components/Code.vue b/app/javascript/dashboard/components/Code.vue
index 17134ebdc..95b09e82c 100644
--- a/app/javascript/dashboard/components/Code.vue
+++ b/app/javascript/dashboard/components/Code.vue
@@ -26,7 +26,8 @@ export default {
},
},
methods: {
- onCopy() {
+ onCopy(e) {
+ e.preventDefault();
copy(this.script);
bus.$emit('newToastMessage', this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
},
diff --git a/app/javascript/dashboard/i18n/locale/en/settings.json b/app/javascript/dashboard/i18n/locale/en/settings.json
index 683490afe..32b982476 100644
--- a/app/javascript/dashboard/i18n/locale/en/settings.json
+++ b/app/javascript/dashboard/i18n/locale/en/settings.json
@@ -18,6 +18,10 @@
"TITLE": "Password",
"NOTE": "Updating your password would reset your logins in multiple devices."
},
+ "ACCESS_TOKEN": {
+ "TITLE": "Access Token",
+ "NOTE": "This token can be used if you are building an API based integration"
+ },
"EMAIL_NOTIFICATIONS_SECTION" : {
"TITLE": "Email Notifications",
"NOTE": "Update your email notification preferences here",
diff --git a/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue
index ecdbace19..c1ffd9b05 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue
@@ -83,6 +83,17 @@
{{ $t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.NOTE') }}
+