# frozen_string_literal: true require "excon" class CustomWizard::Api::Authorization include ActiveModel::SerializerSupport attr_accessor :api_name, :auth_type, :auth_url, :token_url, :client_id, :client_secret, :auth_params, :access_token, :refresh_token, :token_expires_at, :token_refresh_at, :code, :username, :password def initialize(api_name, data = {}) @api_name = api_name data.each { |k, v| self.send "#{k}=", v if self.respond_to?(k) } end def authorized @authorized ||= @access_token && @token_expires_at.to_datetime > Time.now end def self.set(api_name, new_data = {}) api_name = api_name.underscore data = self.get(api_name, data_only: true) || {} new_data.each { |k, v| data[k.to_sym] = v } PluginStore.set("custom_wizard_api_#{api_name}", "authorization", data) self.get(api_name) end def self.get(api_name, opts = {}) api_name = api_name.underscore if data = PluginStore.get("custom_wizard_api_#{api_name}", "authorization") if opts[:data_only] data else self.new(api_name, data) end else nil end end def self.remove(api_name) PluginStore.remove("custom_wizard_api_#{api_name}", "authorization") end def self.authorization_string(name) auth = CustomWizard::Api::Authorization.get(name) raise Discourse::InvalidParameters.new(:name) if auth.blank? if auth.auth_type === "basic" raise Discourse::InvalidParameters.new(:username) if auth.username.blank? raise Discourse::InvalidParameters.new(:password) if auth.password.blank? "Basic #{Base64.strict_encode64((auth.username + ":" + auth.password).chomp)}" elsif %w[oauth_3 oauth_2].include?(auth.auth_type) raise Discourse::InvalidParameters.new(auth.access_token) if auth.access_token.blank? "Bearer #{auth.access_token}" else nil end end def self.get_token(name, opts = {}) authorization = CustomWizard::Api::Authorization.get(name) type = authorization.auth_type body = {} if opts[:refresh] && type === "oauth_3" body["grant_type"] = "refresh_token" elsif type === "oauth_2" body["grant_type"] = "client_credentials" elsif type === "oauth_3" body["grant_type"] = "authorization_code" end unless opts[:refresh] body["client_id"] = authorization.client_id body["client_secret"] = authorization.client_secret end if type === "oauth_3" body["code"] = authorization.code body["redirect_uri"] = Discourse.base_url + "/admin/wizards/apis/#{name}/redirect" end connection = Excon.new( authorization.token_url, headers: { "Content-Type" => "application/x-www-form-urlencoded", }, method: "GET", query: URI.encode_www_form(body), ) begin result = connection.request() log_params = { time: Time.now, user_id: 0, status: "SUCCESS", url: authorization.token_url, error: "", } CustomWizard::Api::LogEntry.set(name, log_params) rescue SystemCallError => e log_params = { time: Time.now, user_id: 0, status: "FAILURE", url: authorization.token_url, error: "Token refresh request failed: #{e.inspect}", } CustomWizard::Api::LogEntry.set(name, log_params) end self.handle_token_result(name, result) end def self.handle_token_result(name, result) result_data = JSON.parse(result.body) return result_data if result_data["error"] data = {} data["access_token"] = result_data["access_token"] data["refresh_token"] = result_data["refresh_token"] if result_data["refresh_token"] data["token_type"] = result_data["token_type"] if result_data["token_type"] if result_data["expires_in"] data["token_expires_at"] = Time.now + result_data["expires_in"].seconds data["token_refresh_at"] = data["token_expires_at"].to_time - 10.minutes opts = { name: name } Jobs.enqueue_at(data["token_refresh_at"], :refresh_api_access_token, opts) end CustomWizard::Api::Authorization.set(name, data) end end