From 752643ecffc96574e5a4e7d63c00d89ed77b5dc1 Mon Sep 17 00:00:00 2001 From: kaiomagalhaes Date: Sun, 30 Aug 2020 10:56:25 -0300 Subject: [PATCH] add slack basic oauth flow --- .env.example | 5 ++- Gemfile | 2 ++ Gemfile.lock | 10 ++++++ app.rb | 48 +++++++++++++++++++++------ controllers/application_controller.rb | 5 +-- models/access_tokens.rb | 18 ++++++++++ models/base_model.rb | 7 ++++ services/Database.rb | 10 ++++++ services/slack_oauth.rb | 26 +++++++++++++++ 9 files changed, 118 insertions(+), 13 deletions(-) create mode 100644 models/access_tokens.rb create mode 100644 models/base_model.rb create mode 100644 services/Database.rb create mode 100644 services/slack_oauth.rb diff --git a/.env.example b/.env.example index 5264f6c..fb0cb4f 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,5 @@ SLACK_API_KEY= -AUTHENTICATION_KEY= \ No newline at end of file +AUTHENTICATION_KEY= +SLACK_CLIENT_ID= +SLACK_CLIENT_SECRET= +DATABASE_URL= \ No newline at end of file diff --git a/Gemfile b/Gemfile index 5a54c9e..343e9c9 100644 --- a/Gemfile +++ b/Gemfile @@ -5,8 +5,10 @@ source "https://rubygems.org" gem "sinatra" gem 'slack-ruby-client' gem 'gelf' +gem 'mongo' group :development, :test do gem "rerun" gem "dotenv" + gem 'pry' end \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 5772bc6..3a0ed0d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,6 +7,8 @@ GEM minitest (~> 5.1) tzinfo (~> 1.1) zeitwerk (~> 2.2, >= 2.2.2) + bson (4.10.0) + coderay (1.1.3) concurrent-ruby (1.1.6) dotenv (2.7.5) faraday (1.0.1) @@ -24,10 +26,16 @@ GEM listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) + method_source (1.0.0) minitest (5.14.1) + mongo (2.13.0) + bson (>= 4.8.2, < 5.0.0) multipart-post (2.1.1) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) rack (2.2.3) rack-protection (2.0.8.1) rack @@ -64,6 +72,8 @@ PLATFORMS DEPENDENCIES dotenv gelf + mongo + pry rerun sinatra slack-ruby-client diff --git a/app.rb b/app.rb index 2a1fc7e..b01d61b 100644 --- a/app.rb +++ b/app.rb @@ -1,4 +1,5 @@ require 'dotenv/load' if ENV["RACK_ENV"] != "production" + require 'sinatra' require 'gelf' require './controllers/channel_messages_controller' @@ -6,23 +7,31 @@ require './controllers/direct_ephemeral_messages_controller' require './controllers/reactions_controller' require './controllers/users_controller' +require './models/access_tokens' +require './services/slack_oauth' configure do set :show_exceptions, false end -before do - content_type :json - body = request.body.read - +def authenticate! key = env['HTTP_AUTHORIZATION'] clean_key = key&.gsub(/Bearer /, '') if clean_key != ENV['AUTHENTICATION_KEY'] halt 401 end +end + +before do + content_type :json + body = request.body.read @body = JSON.parse body if !body.empty? + + if (@body && @body["team"]) + @slack_team_key = AccessTokens.new.by_team_id(@body["team"])[:value] + end end def render_json json @@ -34,27 +43,46 @@ def render_json json end post '/channel-messages' do - ChannelMessagesController.new(@body, response).create! + authenticate! + ChannelMessagesController.new(@body, response, @slack_team_key).create! end patch '/channel-messages' do - ChannelMessagesController.new(@body, response).update! + authenticate! + ChannelMessagesController.new(@body, response, @slack_team_key).update! end post '/direct-messages' do - DirectMessagesController.new(@body, response).create! + authenticate! + DirectMessagesController.new(@body, response, @slack_team_key).create! end post '/direct-ephemeral-messages' do - DirecEphemeraltMessagesController.new(@body, response).create! + authenticate! + DirecEphemeraltMessagesController.new(@body, response, @slack_team_key).create! end post '/reactions' do - ReactionsController.new(@body, response).create! + authenticate! + ReactionsController.new(@body, response, @slack_team_key).create! end get '/users' do - UsersController.new(@body, response).index + authenticate! + UsersController.new(@body, response, @slack_key).index +end + +get '/oauth' do + code = params[:code] + data = SlackOauth.new(code).authenticate! + access_token = data.with_indifferent_access[:access_token] + team_id = data.with_indifferent_access[:team][:id] + + AccessTokens.new.create!(access_token, team_id) + + response.body = JSON.dump({ + status: 'success' + }) end error do diff --git a/controllers/application_controller.rb b/controllers/application_controller.rb index 27ccc18..1f25abd 100644 --- a/controllers/application_controller.rb +++ b/controllers/application_controller.rb @@ -1,8 +1,9 @@ class ApplicationController - def initialize(params, response) + def initialize(params, response, slack_team_key = nil) Slack.configure do |config| - config.token = ENV['SLACK_API_KEY'] + config.token = slack_team_key || ENV['SLACK_API_KEY'] end + @params = params&.with_indifferent_access @response = response end diff --git a/models/access_tokens.rb b/models/access_tokens.rb new file mode 100644 index 0000000..f13b6e6 --- /dev/null +++ b/models/access_tokens.rb @@ -0,0 +1,18 @@ +require './models/base_model' + +class AccessTokens < BaseModel + # @TODO: do not create a new one if there is a team id in the database already + def create!(access_token, team_id) + collection = @client[:access_tokens] + doc = { + value: access_token, + team_id: team_id + } + collection.insert_one(doc) + end + + def by_team_id(team_id) + collection = @client[:access_tokens] + collection.find("team_id": team_id ).first + end +end \ No newline at end of file diff --git a/models/base_model.rb b/models/base_model.rb new file mode 100644 index 0000000..337c411 --- /dev/null +++ b/models/base_model.rb @@ -0,0 +1,7 @@ +require './services/database' + +class BaseModel + def initialize + @client = Database.instance.client + end +end \ No newline at end of file diff --git a/services/Database.rb b/services/Database.rb new file mode 100644 index 0000000..3f593ff --- /dev/null +++ b/services/Database.rb @@ -0,0 +1,10 @@ +require 'mongo' +require 'singleton' + +class Database + include Singleton + + def client + @client ||= client = Mongo::Client.new(ENV['DATABASE_URL']) + end +end \ No newline at end of file diff --git a/services/slack_oauth.rb b/services/slack_oauth.rb new file mode 100644 index 0000000..7a13d12 --- /dev/null +++ b/services/slack_oauth.rb @@ -0,0 +1,26 @@ +require 'uri' +require 'net/http' + +class SlackOauth + SLACK_AUTHENTICATE_URL = 'https://slack.com/api/oauth.v2.access' + + def initialize(code) + @code = code + end + + def authenticate! + data = { + :code => @code, + :client_id => ENV['SLACK_CLIENT_ID'], + :client_secret => ENV['SLACK_CLIENT_SECRET'], + } + + encoded_data = URI.encode_www_form(data) + + url = URI.parse("#{SLACK_AUTHENTICATE_URL}?#{encoded_data}") + http = Net::HTTP.new(url.host, url.port) + http.use_ssl = true + req = Net::HTTP::Get.new(url.request_uri) + JSON.parse(http.request(req).body) + end +end \ No newline at end of file