发送POST请求时Ruby的机械化错误401(Steam交易要约发送)

时间:2018-04-19 19:17:03

标签: ruby mechanize

我试图使用机械化发送蒸汽交易报价,我登录获取所需的cookie但是当我尝试发送蒸汽交易报价时,我收到错误401未经授权。

我从python中移植this code只有区别,据我所知,也许python的请求库处理POST请求中的cookie与ruby的机械化相比,你可以通过输出机械化Cookie并根据this验证我是否在登录请求中获取了所有Cookie我已经拥有了所有必需的Cookie

这是我的代码,你可以复制粘贴它并执行它的工作唯一的问题是最后一行。

require 'mechanize'
require 'json'
require 'open-uri'
require 'openssl'
require 'base64'
require 'time'

def fa(shared_secret)
      timestamp = Time.new.to_i
      math = timestamp / 30
      math = math.to_i
      time_buffer =[math].pack('Q>')

      hmac = OpenSSL::HMAC.digest('sha1', Base64.decode64(shared_secret), time_buffer)

      start = hmac[19].ord & 0xf
      last = start + 4
      pre = hmac[start..last]
      fullcode = pre.unpack('I>')[0] & 0x7fffffff

      chars = '23456789BCDFGHJKMNPQRTVWXY'
      code= ''
      for looper in 0..4 do
        copy = fullcode #divmod
        i = copy % chars.length #divmod
        fullcode = copy / chars.length #divmod
        code = code + chars[i]
      end
      puts code
      return code

end

def pass_stamp(username,password,mech)
      response = mech.post('https://store.steampowered.com/login/getrsakey/', {'username' => username})

      data = JSON::parse(response.body)
      mod = data["publickey_mod"].hex
      exp = data["publickey_exp"].hex
      timestamp = data["timestamp"]

      key   = OpenSSL::PKey::RSA.new
      key.e = OpenSSL::BN.new(exp)
      key.n = OpenSSL::BN.new(mod)
      ep = Base64.encode64(key.public_encrypt(password.force_encoding("utf-8"))).gsub("\n", '')
      return {'password' => ep, 'timestamp' => timestamp }
end

user = 'user'
password = 'password'

session = Mechanize.new { |agent|
  agent.user_agent_alias = 'Windows Mozilla'
  agent.follow_meta_refresh = true
  agent.add_auth('https://steamcommunity.com/tradeoffer/new/send/', user, password)
  agent.log = Logger.new("mech.log")
}

data = pass_stamp(user,password, session)
ep = data["password"]
timestamp = data["timestamp"]
session.add_auth('https://steamcommunity.com/tradeoffer/new/send/', user,  ep)

send = {
      'password' => ep,
      'username' => user,
      'twofactorcode' =>fa('twofactorcode'), #update
      'emailauth' => '',
      'loginfriendlyname' => '',
      'captchagid' => '-1',
      'captcha_text' => '',
      'emailsteamid' => '',
      'rsatimestamp' => timestamp,
      'remember_login' => 'false'
}

login = session.post('https://store.steampowered.com/login/dologin', send )
responsejson = JSON::parse(login.body)
if responsejson["success"] != true
      puts "didn't sucded"
      puts "probably 2fa code time diffrence,  retry "
      exit
end

responsejson["transfer_urls"].each { |url|
      getcookies = session.post(url, responsejson["transfer_parameters"])
}

session.get("https://steamcommunity.com/") do |page| ## to verify that you are logged in check this HTML
     File.open('./body.html', 'w') {|f| f.puts page.content}
end

sessionid = ''
session.cookies.each { |c|
      string = c.dup.to_s
      if string.include?('sessionid')
            sessionid = string.gsub('sessionid=', '')
      end
}

offer_link = 'https://steamcommunity.com/tradeoffer/new/?partner=410155236&token=H-yK-GFt'
token = offer_link.split('token=', 2)[1]
theirs = [{"appid" => 753,"contextid"=> "6","assetid" => "6705710171","amount" => 1 }]
mine =  []
params = {
      'sessionid' => sessionid,
      'serverid' => 1,
      'partner' => '76561198370420964',
      'tradeoffermessage' => '',
      'json_tradeoffer' => {
            "new_version" => true,
           "version" => 4,
           "me" => {
                "assets" => mine, #create this array
                "currency" => [],
                "ready" => false
           },
           "them" => {
           "assets" => theirs, #create this array
           "currency" => [],
           "ready" => false
            }
      },
      'captcha' => '',
      'trade_offer_create_params' => {'trade_offer_access_token' => token}
}
#the issue begins from here
begin
      send_offer = session.post(
        'http://steamcommunity.com/tradeoffer/new/send/',
        params,
        {'Referer' =>  "#{offer_link}", 'Origin' => 'https://steamcommunity.com/tradeoffer/new/send' }
      )
      puts send_offer.body
rescue Mechanize::UnauthorizedError => e
      puts e
      puts e.page.content
end

1 个答案:

答案 0 :(得分:0)

我通过调试python POST请求找到了问题。 发生了什么:当我登录时,我确实得到了一个sessionid,但是该sessionid对'store.steampowered.com'和'help.steampowered.com'有效'.storesteapowered.com'有效。 在我的代码中我盲目地识别我的会话cookie(没有注意它属于哪个网站),因此在POST请求参数中发送的sessionid变量不等于POST请求发送的cookie。标题所以我得到了401 Unauthorized。

所以我们需要设置/获取steamcommunity.com的会话ID。 修复:

1)为steamcommunity.com设置一个随机的CSRF sessionid cookie,或者像我一样,将steampowered.com的会话ID cookie设置为steamcommunity.com(在代码中标记)

<{1}}中的

2)应为params => 'json_tradeoffer' => "new_version"以避免错误400 BAD REQUEST

3)帖子请求的标题应为:

"newversion"

4)转换{'Referer' =>'https://steamcommunity.com/tradeoffer/new', 'Origin' =>'https://steamcommunity.com' } &amp;使用to_json

params => json_tradeoffer值设置为字符串

重要:此代码适用于1个优惠发送,如果您要发送超过1个必须始终更新您的sessionid变量,因为Cookie值将每次更改与steamcommunity.com沟通的时间

这里是修复的代码:

params =>  'trade_offer_create_params'