# typed: strict require 'json' require 'httparty' require_relative '../structs/signature' require_relative '../structs/task' module Researchable module FreedcampApi module Sessions class SignedSession < Session extend T::Sig extend T::Helpers BASE = T.let('https://freedcamp.com/api/v1'.freeze, String) HEADERS = T.let({ 'Content-Type' => 'application/x-www-form-urlencoded' }.freeze, T::Hash[T.untyped, T.untyped]) # rubocop:disable Style/AccessorGrouping sig { returns(String) } attr_reader :public_key sig { returns(String) } attr_reader :secret_key # rubocop:enable Style/AccessorGrouping sig { params(public_key: String, secret_key: String).void } def initialize(public_key: ENV['PUBLIC_KEY'], secret_key: ENV['SECRET_KEY']) @public_key = public_key @secret_key = secret_key @debug = false end sig { override.params(path: String).returns(T::Hash[T.untyped, T.untyped]) } def get(path) call_url(path, :get) end # (3) sig do override.params( path: String, data: T.any( Researchable::FreedcampApi::Structs::Task, Researchable::FreedcampApi::Structs::Comment, T::Hash[T.untyped, T.untyped] ) ).returns(T.untyped) end def post(path, data) call_url(path, :post, data) end private sig do params( path: String, method: Symbol, data: T.any( Researchable::FreedcampApi::Structs::Task, Researchable::FreedcampApi::Structs::Comment, T::Hash[T.untyped, T.untyped] ) ).returns(T::Hash[T.untyped, T.untyped]) end def call_url(path, method, data = {}) content = render_call(path, method, data) content = JSON.parse(content) if content content end def render_call(path, method, data) signature = generate_signature url = make_url(path, signature) data = serialize_data(data) puts url if @debug HTTParty.send(method, url, body: data, headers: HEADERS).body end def serialize_data(data = {}) return {} if data == {} data = data.serialize if data.is_a? T::Struct data = { data: data.to_json } end sig { params(path: String, signature: Signature).returns(String) } def make_url(path, signature) result = BASE + path sep = result.include?('?') ? '&' : '?' result += "#{sep}api_key=#{signature.api_key}×tamp=#{signature.timestamp}&hash=#{signature.calculated_hash}" result = result.gsub(/\n\s+/, '') puts result if @debug result end sig { returns(Signature) } def generate_signature time = Time.new.to_i * 1000 data = "#{@public_key}#{time}" signature = OpenSSL::HMAC.hexdigest('sha1', @secret_key, data) Signature.new( timestamp: time, api_key: @public_key, calculated_hash: signature ) end end end end end