Jump to content
McKay Development

Recommended Posts

Posted

I'm writing a SteamBot to send offers to different accounts and to automatically confirm these offers after this. But I'm getting 'Error: Could not act on confirmation' when trying to respond to every confirmation. Can you suggest what am I doing wrong?

 

Here is how I'm using steamcommunity (I'm using babel to transpile all of this into ES5):

class SteamBot {

  // this class has a login function, which logs bot in,
  // and also some fields like 'shared' and 'identity'
  // this.community is a SteamCommunity object

  confirmAll() {
    return new Promise((res, rej) => {
      const time = Math.floor(Date.now() / 1000)
      const key = SteamTotp.getConfirmationKey(this.identity, time, 'conf')

      this.community.getConfirmations(time, key, async (err, confirmations) => {
        if (err)
          return rej(err)

        log(confirmations.map(JSON.stringify).join(', ')) // just for debugging
        for (let confirmation of confirmations) {
          try {
            const confirmRes = await this.confirmConfirmation(confirmation)
            log(`Confirmed ${confirmation.creator}`, true, true)
          } catch (e) {
            log(`Confirmation failed: ${e}`, true, true)
            return rej(e)
          }
        }
        return res(confirmations)
      });
    })
  }

  confirmConfirmation(confirmation) {
    return new Promise((res, rej) => {
      const time = Math.floor(Date.now() / 1000)
      const key = SteamTotp.getConfirmationKey(this.identity, time, 'allow')

      console.log(this.identity) // for debugging purposes
      console.log(confirmation) // also for this

      confirmation.respond(time, key, true, (err) => {
        if (err)
          return rej(err)

        return res()
      })
    })
  }

  constructor(login, password, shared, identity) {
    this.login = login
    this.password = password
    this.shared = shared
    this.identity = identity
    this.loginBot() // logging in, not necessary for now, since it's working okay
  }
}

var bot = new SteamBot(login, password, shared, identity)
// and after logging in and sending tradeoffer, I'm trying to do this:
bot.confirmAll()

I've tried to send offer to my other account and to confirm it immediately, and after that call bot.confirmAll(). It shows that I have confirmations, but when I try to respond to them, it shows an error: 'Could not act on confirmation'.

 

I'm pretty sure that I'm using the right identity_secret (since I've used it with startConfirmationChecker() and everything worked fine, also I console.log()'ed it inside a function just to make sure it's the right one and yes, it's the right one).

 

I'm not sure what I did wrong, I've seen an example that worked pretty much the same (well, without Promises and ES6 stuff, but still), so if you know what could I do wrong, can you suggest me?

 

Thanks in advance.

Posted

I believe your problem is stemming from the fact that you're trying to confirm all your pending confirmations at once. A key can only be used once, so if you try to confirm multiple confirmations in the same second, you'll generate the same key so it won't work.

Posted

I've tried this when there was only one confirmation, it also didn't work and the error was the same so I don't think that's why it's not working. I'll still try to check it once more, just to make sure.

 

Anyway, if this is indeed the cause of the problem, how can I avoid this? I know that I can do something like confirmations[0].respond(...), but is there a way to confirm all confirmation at once?

Posted

I've tried to rewrite confirmAll() this way:

confirmAll() {
    return new Promise((res, rej) => {
      const time = Math.floor(Date.now() / 1000)
      const confKey = SteamTotp.getConfirmationKey(this.identity, time, 'conf')
      const allowKey = SteamTotp.getConfirmationKey(this.identity, time, 'allow')

      this.community.acceptAllConfirmations(time, confKey, allowKey, (err, confirmations) => {
        if (err)
          return rej(err)

        return res(confirmations)
      })
    })
  }

And it still shows 'Error: Could not act on confirmation'

 

What can cause this? I think it's not time-related issue (I tried to set the wrong time for this function, the error was different). Also I'm pretty sure it's not the wrong identity (since I've used the same identity with startConfirmationChecker() and it worked okay).

 

Here is my error stacktrace, in case it will help:

December 12th 2016 23:34:27.465 confirm error Error: Could not act on confirmation
    at /all/Documents/Programming/bot/node_modules/steamcommunity/components/confirmations.js:145:12
    at SteamCommunity.<anonymous> (/all/Documents/Programming/bot/node_modules/steamcommunity/components/confirmations.js:256:3)
    at Request._callback (/all/Documents/Programming/bot/node_modules/steamcommunity/components/http.js:68:15)
    at Request.self.callback (/all/Documents/Programming/bot/node_modules/steamcommunity/node_modules/request/request.js:186:22)
    at emitTwo (events.js:106:13)
    at Request.emit (events.js:191:7)
    at Request.<anonymous> (/all/Documents/Programming/bot/node_modules/steamcommunity/node_modules/request/request.js:1060:10)
    at emitOne (events.js:96:13)
    at Request.emit (events.js:188:7)
    at IncomingMessage.<anonymous> (/all/Documents/Programming/bot/node_modules/steamcommunity/node_modules/request/request.js:980:12)

 

Posted

I suppose if I can send a tradeoffer (with status pending) then I'm logged in.

Also I have some log statements for login errors and I have nothing related to login errors in my console.

 

Here is a complete .js file I'm using for managing bot, if it will help.

import SteamUser from 'steam-user'
import SteamTotp from 'steam-totp'
import TradeOfferManager from 'steam-tradeoffer-manager'
import SteamCommunity from 'steamcommunity'
import { log, sleep } from './utils'

function getRandomInt(min, max) {
  return Math.floor(Math.random() * ((max - min) + 1)) + min
}

class SteamBot {
  loginBot() {
    log(`[bot] Logging in, login [${this.login}] \
password [${this.password}] shared [${this.shared}] \
identity [${this.identity}]`)

    this.status = { name: this.login, loggedIn: false, gotApiKey: false, error: null }

    this.client = new SteamUser()
    this.client.setOption('promptSteamGuardCode', false)
    this.community = new SteamCommunity()

    const authCode = SteamTotp.getAuthCode(this.shared)

    const logOnOptions = {
      accountName: this.login,
      password: this.password,
      twoFactorCode: authCode,
    }

    this.client.on('loggedOn', () => {
      this.status.loggedIn = true
      log(`[bot] Logged into Steam as ${this.client.steamID.getSteam3RenderedID()}`)
      this.client.setPersona(SteamUser.EPersonaState.Online)
    })

    this.client.on('steamGuard', (domain, callback) => {
      log('[bot] Requiring Steam Guard, waiting 30 sec...', true, true)
      setTimeout(() => {
        const code = SteamTotp.getAuthCode(this.shared)
        callback(code)
      }, 30000) // 30 sec sleeping
    })

    this.client.on('error', error => this.onBotLoginError(error))

    this.manager = new TradeOfferManager({
      steam: this.client,
      community: this.community,
      domain: "localhost",
      language: 'en',
      pollInterval: 5000
    })

    this.client.on('webSession', (sessionID, cookies) =>
      this.onBotWebSession(sessionID, cookies))
    this.client.logOn(logOnOptions)
  }

  onBotWebSession(sessionID, cookies) {
    this.manager.setCookies(cookies, err =>
      this.onManagerSetCookies(err))

    this.community.setCookies(cookies)
    this.community.startConfirmationChecker(10000, this.identity);
  }

  onManagerSendOfferChanged(offer, old) {
    log(`[bot] Offer #${offer.id} status: ${TradeOfferManager.ETradeOfferState[offer.state]}`, true, true)
  }


  makeOffer(id, itemsToGive, itemsToReceive, token) {
    return new Promise((res, rej) => {
      const offer = this.manager.createOffer(id)
      offer.itemsToGive = itemsToGive.map(i => ({
        appid: 730,
        contextid: 2,
        amount: 1,
        assetid: i
      }))
      offer.itemsToReceive = itemsToReceive.map(i => ({
        appid: 730,
        contextid: 2,
        amount: 1,
        assetid: i
      }))
      offer.setToken(token)
      offer.send((err, status) => {
        if (err)
          return rej(err)

        this.community.checkConfirmations()
        res(`Sent offer ${offer.id}, status: ${status}`)
      })
    })
  }

  onManagerSetCookies(err) {
    if (err) {
      this.status.error = err.message
      log(`[bot] Error getting API key: ${err.message}`)
      if (err.message === 'HTTP error 429') { // too many requests
        const interval = getRandomInt(60, 300)
        log(`[bot] Too many requests, relogin in ${interval} seconds`, true, true)
        this.client.logOff()
        setTimeout(() => {
          this.loginBot()
        }, interval * 1000) // 60-300 sec sleeping
      } else
        log(`[bot] Unrecoverable error, not retrying. Error: ${err.message}`, true)
      return
    }

    this.status.gotApiKey = true
    log(`[bot] Got API key: ${this.manager.apiKey}`)
    this.manager.on('newOffer', (offer, old) =>
      this.onManagerNewOffer(offer, old))

    this.manager.on('sentOfferChanged', (offer, old) =>
      this.onManagerSendOfferChanged(offer, old))

    this.community.on('newConfirmation', (confirmation) =>
      this.onCommunityNewConfirmation(confirmation));

    this.community.on('confirmationAccepted', (confirmation) =>
      this.onCommunityConfirmationAccepted(confirmation));

    this.community.on('confKeyNeeded', (tag, callback) =>  {
      const time = Math.floor(Date.now() / 1000)
      log(`Conf Key Needed ${JSON.stringify(tag)}`, true, true)
      callback(null, time, SteamTotp.generateAuthCode(this.identity, time, tag))
    })
  }

  onCommunityNewConfirmation(confirmation) {
    log(`Confirmation needed: ${JSON.stringify(confirmation)}`, true, true)
  }

  onCommunityConfirmationAccepted(confirmation) {
    log(`Confirmation accepted: ${JSON.stringify(confirmation)}`, true, true)
  }

  confirmAll() {
    return new Promise((res, rej) => {
      const time = Math.floor(Date.now() / 1000)
      const confKey = SteamTotp.getConfirmationKey(this.identity + 'aaa', time, 'conf')
      const allowKey = SteamTotp.getConfirmationKey(this.identity + 'aaa', time, 'allow')

      this.community.acceptAllConfirmations(time, confKey, allowKey, (err, confirmations) => {
        if (err)
          return rej(err)

        return res(confirmations)
      })
    })
  }

  onManagerNewOffer(offer) {
    const steamId = offer.partner.getSteamID64()
    log(`[bot] New offer #${offer.id}: ${TradeOfferManager.ETradeOfferState[offer.state]} from ${steamId}`, true, true)
    offer.accept(err => {
      if (err) {
        log(`[bot] Offer ${offer.id} error: ${err}`, true, true)
      } else {
        log(`[bot] Offer from ${steamId} accepted: ${offer.id}`, true, true);
      }
    })
  }

  onBotLoginError(error) {
    this.status.loggedIn = false
    this.status.error = error.message

    const interval = getRandomInt(5, 15)
    log(`[bot] Error logging in: ${error.message}, sleeping for ${interval} min...`, true, true)
    setTimeout(() => {
      this.loginBot()
    }, interval * 1000 * 60) // 5-15 min sleeping
  }

  constructor(login, password, shared, identity) {
    this.login = login
    this.password = password
    this.shared = shared
    this.identity = identity
    this.loginBot()
  }
}

export default SteamBot

Posted

Make sure you aren't trying to double-confirm things, I suppose. When accepting a confirmation fails, all Steam returns is {"success":false} which is what triggers this error. Unfortunately, there's no more detail.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...