· 10 years ago · Mar 22, 2016, 05:54 PM
1var fs = require('fs');
2var crypto = require('crypto');
3var console = process.console;
4var config = require('./config.js');
5var Steam = require('steam');
6var SteamWebLogOn = require('steam-weblogon');
7var getSteamAPIKey = require('steam-web-api-key');
8var SteamTradeOffers = require('steam-tradeoffers');
9var SteamCommunity = require('steamcommunity');
10var SteamcommunityMobileConfirmations = require('steamcommunity-mobile-confirmations');
11var SteamTotp = require('steam-totp');
12var redisClient, io, requestify;
13
14module.exports.init = function (redis, ioSocket, requestifyCore) {
15 io = ioSocket;
16 redisClient = redis.createClient();
17 requestify = requestifyCore;
18}
19
20var details = {
21 account_name: config.bot.username,
22 password: config.bot.password,
23 two_factor_code: generatekey(config.bot.secret)
24};
25
26var steamClient = new Steam.SteamClient();
27var steamUser = new Steam.SteamUser(steamClient);
28var steamFriends = new Steam.SteamFriends(steamClient);
29var steamWebLogOn = new SteamWebLogOn(steamClient, steamUser);
30var offers = new SteamTradeOffers();
31
32// Generation Device_ID
33var hash = require('crypto').createHash('sha1');
34hash.update(Math.random().toString());
35hash = hash.digest('hex');
36var device_id = 'android:' + hash;
37
38var checkingOffers = [],
39 WebCookies = [],
40 WebSession = false,
41 globalSession;
42
43const redisChannels = {
44 checkItemsList: 'checkItems.list',
45 checkList: 'check.list',
46 checkedList: 'checked.list',
47 betsList: 'bets.list',
48 sendOffersList: 'send.offers.list',
49 tradeoffersList: 'tradeoffers.list',
50 declineList: 'decline.list',
51 usersQueue: 'usersQueue.list',
52}
53
54function steamBotLogger(log) {
55 console.tag('БОТ').log(log);
56}
57
58function EscrowLogger(log) {
59 console.tag('ЕÑкроу Бот').info(log);
60}
61
62function generatekey(secret) {
63 code = SteamTotp.generateAuthCode(secret);
64 EscrowLogger('Сгенерированный код : ' + code);
65 return code;
66}
67
68steamClient.connect();
69steamClient.on('debug', steamBotLogger);
70steamClient.on('connected', function () {
71 steamUser.logOn(details);
72});
73
74steamClient.on('logOnResponse', function (logonResp) {
75 if (logonResp.eresult === Steam.EResult.OK) {
76 steamBotLogger('ЗалогинилÑÑ!');
77 steamFriends.setPersonaState(Steam.EPersonaState.Online);
78
79 steamWebLogOn.webLogOn(function (sessionID, newCookie) {
80 getSteamAPIKey({
81 sessionID: sessionID,
82 webCookie: newCookie
83 }, function (err, APIKey) {
84 offers.setup({
85 sessionID: sessionID,
86 webCookie: newCookie,
87 APIKey: APIKey
88 }, function (err) {
89 WebSession = true;
90 globalSession = sessionID;
91 WebCookies = newCookie;
92 redisClient.lrange(redisChannels.tradeoffersList, 0, -1, function (err, offers) {
93 offers.forEach(function (offer) {
94 checkingOffers.push(offer);
95 });
96 handleOffers();
97 AcceptMobileOffer();
98 });
99 steamBotLogger('ÐаÑтройка трейдов!');
100 });
101
102 });
103 });
104 }
105});
106
107function handleOffers() {
108 offers.getOffers({
109 get_received_offers: 1,
110 active_only: 1
111 }, function (error, body) {
112 if (
113 body
114 && body.response
115 && body.response.trade_offers_received
116 ) {
117 body.response.trade_offers_received.forEach(function (offer) {
118 if (offer.trade_offer_state == 2) {
119 if (is_checkingOfferExists(offer.tradeofferid)) return;
120
121 if (offer.items_to_give != null && config.admins.indexOf(offer.steamid_other) != -1) {
122 console.tag('БОТ', 'Трейд').log('Трейд #' + offer.tradeofferid + ' От: ÐДМИÐÐ ' + offer.steamid_other);
123 offers.acceptOffer({tradeOfferId: offer.tradeofferid});
124 return;
125 }
126 if (offer.items_to_give != null) {
127 offers.declineOffer({tradeOfferId: offer.tradeofferid});
128 return;
129 }
130 offers.getTradeHoldDuration({tradeOfferId: offer.tradeofferid}, function (err, response) {
131 if (err) {
132 steamBotLogger('Отклонение. Ðету ESCROW: ' + err);
133 offers.declineOffer({tradeOfferId: offer.tradeofferid});
134 steamBotLogger('Отклонение. Ðету ESCROW: ' + offer.tradeofferid);
135 return;
136 } else if (response.their != 0) {
137 steamBotLogger('response.their: ' + response.their);
138 offers.declineOffer({tradeOfferId: offer.tradeofferid});
139 steamBotLogger('Отклонение. Ðету ESCROW: ' + offer.tradeofferid);
140 return;
141 }
142 });
143 if (offer.items_to_receive != null && offer.items_to_give == null) {
144 checkingOffers.push(offer.tradeofferid);
145 console.tag('БОТ', 'Трейдофферы').log('Трейд #' + offer.tradeofferid + ' От: ' + offer.steamid_other);
146 redisClient.multi([
147 ['rpush', redisChannels.tradeoffersList, offer.tradeofferid],
148 ['rpush', redisChannels.checkItemsList, JSON.stringify(offer)],
149 ['rpush', redisChannels.usersQueue, offer.steamid_other]
150 ]).exec(function () {
151 redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
152 io.sockets.emit('queue', queues);
153 });
154 });
155 return;
156 }
157 }
158 });
159 }
160 });
161}
162
163steamUser.on('tradeOffers', function (number) {
164 if (number > 0) {
165 handleOffers();
166 }
167});
168
169
170var parseOffer = function (offer, offerJson) {
171 offers.loadPartnerInventory({
172 partnerSteamId: offer.steamid_other,
173 appId: 730,
174 contextId: 2,
175 tradeOfferId: offer.tradeofferid,
176 language: "russian"
177 }, function (err, hitems) {
178 if (err) {
179 redisClient.multi([
180 ['rpush', redisChannels.declineList, offer.tradeofferid],
181 ['lrem', redisChannels.checkItemsList, 0, offerJson],
182 ['lrem', redisChannels.usersQueue, 1, offer.steamid_other]
183 ])
184 .exec(function (err, replies) {
185 parseItemsProcceed = false;
186 return;
187 });
188 return;
189 }
190 var items = offer.items_to_receive;
191 var items_to_check = [], num = 0;
192 for (var i = 0; i < items.length; i++) {
193 for (var j = 0; j < hitems.length; j++) {
194 if (items[i].assetid == hitems[j].id) {
195 items_to_check[num] = {
196 appid: hitems[j].appid,
197 name: hitems[j].market_name,
198 market_hash_name: hitems[j].market_hash_name,
199 classid: hitems[j].classid
200 };
201 var type = hitems[j].type;
202 var rarity = '';
203 var arr = type.split(',');
204 if (arr.length == 2) type = arr[1].trim();
205 if (arr.length == 3) type = arr[2].trim();
206 if (arr.length && arr[0] == 'Ðож') type = '★';
207 switch (type) {
208 case 'ÐрмейÑкое качеÑтво':
209 rarity = 'milspec';
210 break;
211 case 'Запрещенное':
212 rarity = 'restricted';
213 break;
214 case 'ЗаÑекреченное':
215 rarity = 'classified';
216 break;
217 case 'Тайное':
218 rarity = 'covert';
219 break;
220 case 'Ширпотреб':
221 rarity = 'common';
222 break;
223 case 'Промышленное качеÑтво':
224 rarity = 'common';
225 break;
226 case '★':
227 rarity = 'rare';
228 break;
229 }
230 items_to_check[num].rarity = rarity;
231 num++;
232 break;
233 }
234 }
235 }
236 var value = {
237 offerid: offer.tradeofferid,
238 accountid: offer.steamid_other,
239 items: JSON.stringify(items_to_check)
240 };
241
242 console.tag('БОТ', 'Трейд #' + value.offerid).log(value);
243
244 redisClient.multi([
245 ['rpush', redisChannels.checkList, JSON.stringify(value)],
246 ['lrem', redisChannels.checkItemsList, 0, offerJson]
247 ])
248 .exec(function (err, replies) {
249 parseItemsProcceed = false;
250 });
251
252 });
253}
254
255var checkOfferPrice = function () {
256 requestify.get('http://' + config.domain + '/api/checkOffer', {
257 secretKey: config.secretKey
258 })
259 .then(function (response) {
260 var answer = JSON.parse(response.body);
261
262 if (answer.success) {
263 checkProcceed = false;
264 }
265 }, function (response) {
266 console.tag('БОТ').error('Something wrong with check offers. Retry...');
267 setTimeout(function () {
268 checkOfferPrice()
269 }, 1000);
270 });
271
272}
273
274var checkNewBet = function () {
275 requestify.post('http://' + config.domain + '/api/newBet', {
276 secretKey: config.secretKey
277 })
278 .then(function (response) {
279 var answer = JSON.parse(response.body);
280 if (answer.success) {
281 betsProcceed = false;
282 }
283 }, function (response) {
284 console.tag('БОТ').error('Something wrong with send a new bet. Retry...');
285 setTimeout(function () {
286 checkNewBet()
287 }, 1000);
288 });
289}
290
291var checkArrGlobal = [];
292
293var sendTradeOffer = function (appId, partnerSteamId, accessToken, sendItems, message, game, offerJson) {
294 try {
295 offers.loadMyInventory({
296 appId: appId,
297 contextId: 2
298 }, function (err, items) {
299 if (err) {
300 console.log(err);
301 sendProcceed = false;
302 return;
303 }
304 var itemsFromMe = [],
305 checkArr = [],
306 num = 0;
307 var i = 0;
308 for (var i = 0; i < sendItems.length; i++) {
309 for (var j = 0; j < items.length; j++) {
310 if (items[j].tradable && (items[j].classid == sendItems[i])) {
311 if ((checkArr.indexOf(items[j].id) == -1) && (checkArrGlobal.indexOf(items[j].id) == -1)) {
312 checkArr[i] = items[j].id;
313 itemsFromMe[num] = {
314 appid: 730,
315 contextid: 2,
316 amount: items[j].amount,
317 assetid: items[j].id
318 };
319 num++;
320 break;
321 }
322 }
323 }
324 }
325 if (num > 0) {
326 offers.makeOffer({
327 partnerSteamId: partnerSteamId,
328 accessToken: accessToken,
329 itemsFromMe: itemsFromMe,
330 itemsFromThem: [],
331 message: 'ПоздравлÑем Ñ Ð¿Ð¾Ð±ÐµÐ´Ð¾Ð¹ на Ñайте' + config.domain + '| Ð’ игре #' + game
332 }, function (err, response) {
333 if (err) {
334 console.tag('БОТ', 'Отправка выигрыша').error('Ошибка отправки выигрыша:' + err.message);
335 getErrorCode(err.message, function (errCode) {
336 if (errCode == 15 || errCode == 25 || err.message.indexOf('Ошибка отправки вашего трейда. Попробуйте позже!')) {
337 redisClient.lrem(redisChannels.sendOffersList, 0, offerJson, function (err, data) {
338 setPrizeStatus(game, 2);
339 sendProcceed = false;
340 });
341 sendProcceed = false;
342 }
343 sendProcceed = false;
344 });
345 return;
346 }
347 checkArrGlobal = checkArrGlobal.concat(checkArr);
348 redisClient.lrem(redisChannels.sendOffersList, 0, offerJson, function (err, data) {
349 setPrizeStatus(game, 1);
350 sendProcceed = false;
351 });
352 console.tag('БОТ', 'Отправка выигрыша').log('Трейд #' + response.tradeofferid + ' отправлен!');
353 AcceptMobileOffer();
354 });
355 } else {
356 console.tag('БОТ', 'Отправка выигрыша').log('Вещи не найдены!');
357 redisClient.lrem(redisChannels.sendOffersList, 0, offerJson, function (err, data) {
358 setPrizeStatus(game, 1);
359 sendProcceed = false;
360 });
361 }
362 });
363
364 } catch (ex) {
365 console.tag('БОТ').error('Ошибка отправки выигрыша');
366 setPrizeStatus(game, 2);
367 sendProcceed = false;
368 }
369};
370
371var setPrizeStatus = function (game, status) {
372 requestify.post('http://' + config.domain + '/api/setPrizeStatus', {
373 secretKey: config.secretKey,
374 game: game,
375 status: status
376 })
377 .then(function (response) {
378
379 }, function (response) {
380 console.tag('БОТ').log('Ошибка Ñ ÑтатуÑом приза. Перепробываем...');
381 setTimeout(function () {
382 setPrizeStatus()
383 }, 1000);
384 });
385}
386
387var is_checkingOfferExists = function (tradeofferid) {
388 for (var i = 0, len = checkingOffers.length; i < len; ++i) {
389 var offer = checkingOffers[i];
390 if (offer == tradeofferid) {
391 return true;
392 break;
393 }
394 }
395 return false;
396}
397
398var checkedOffersProcceed = function (offerJson) {
399 var offer = JSON.parse(offerJson);
400 if (offer.success) {
401 console.tag('БОТ').log('ПроцеÑÑ Ð¿Ñ€Ð¸Ð½ÑÑ‚Ð¸Ñ Ñ‚Ñ€ÐµÐ¹Ð´Ð°: #' + offer.offerid);
402 offers.acceptOffer({tradeOfferId: offer.offerid}, function (err, body) {
403 if (!err) {
404 redisClient.multi([
405 ["lrem", redisChannels.tradeoffersList, 0, offer.offerid],
406 ["lrem", redisChannels.usersQueue, 1, offer.steamid64],
407 ["rpush", redisChannels.betsList, offerJson],
408 ["lrem", redisChannels.checkedList, 0, offerJson]
409 ])
410 .exec(function (err, replies) {
411 redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
412 io.sockets.emit('queue', queues);
413 console.tag('БОТ').log("Ставка принÑта!");
414 checkedProcceed = false;
415 });
416 });
417 AcceptMobileOffer();
418 } else {
419 console.tag('БОТ').error('Ошибка при принÑтии трейда #' + offer.offerid)
420 .tag('БОТ').log(err);
421
422 offers.getOffer({tradeOfferId: offer.offerid}, function (err, body) {
423 if (body.response.offer) {
424 var offerCheck = body.response.offer;
425 if (offerCheck.trade_offer_state == 2) {
426 checkedProcceed = false;
427 return;
428 }
429 if (offerCheck.trade_offer_state == 3) {
430 redisClient.multi([
431 ["lrem", redisChannels.tradeoffersList, 0, offer.offerid],
432 ["lrem", redisChannels.usersQueue, 1, offer.steamid64],
433 ["rpush", redisChannels.betsList, offerJson],
434 ["lrem", redisChannels.checkedList, 0, offerJson]
435 ])
436 .exec(function (err, replies) {
437 redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
438 io.sockets.emit('queue', queues);
439 checkedProcceed = false;
440 });
441 });
442 } else {
443 redisClient.multi([
444 ["lrem", redisChannels.tradeoffersList, 0, offer.offerid],
445 ["lrem", redisChannels.usersQueue, 1, offer.steamid64],
446 ["lrem", redisChannels.checkedList, 0, offerJson]
447 ])
448 .exec(function (err, replies) {
449 redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
450 io.sockets.emit('queue', queues);
451 checkedProcceed = false;
452 });
453 });
454 }
455 }
456 })
457 }
458 });
459 }
460}
461
462function AcceptMobileOffer() {
463 // Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð´Ð»Ñ Ð¼Ð¾Ð±Ð¸Ð»ÑŒÐ½Ñ‹Ñ… подтверждений
464 var steamcommunityMobileConfirmations = new SteamcommunityMobileConfirmations(
465 {
466 steamid: config.bot.steamid,
467 identity_secret: config.bot.identity_secret,
468 device_id: device_id,
469 webCookie: WebCookies,
470 });
471
472 steamcommunityMobileConfirmations.FetchConfirmations((function (err, confirmations) {
473 if (err) {
474 console.log(err);
475 return;
476 }
477 console.tag('БОТ', 'Мобильное подтверждение').log('Трейдов в ожидании: ' + confirmations.length);
478 if (!confirmations.length) {
479 return;
480 }
481 steamcommunityMobileConfirmations.AcceptConfirmation(confirmations[0], (function (err, result) {
482 if (err) {
483 console.log(err);
484 return;
485 }
486 console.tag('БОТ', 'Мобильное подтверждение').log('Результат: ' + result);
487 }).bind(this));
488 }).bind(this));
489}
490
491var declineOffersProcceed = function (offerid) {
492 console.tag('БОТ').log('ПроцеÑÑ Ð¾Ñ‚ÐºÐ»Ð¾Ð½ÐµÐ½Ð¸Ñ: #' + offerid);
493 offers.declineOffer({tradeOfferId: offerid}, function (err, body) {
494 if (!err) {
495 console.tag('БОТ').log('Трейд #' + offerid + ' Отклонен!');
496 redisClient.lrem(redisChannels.declineList, 0, offerid);
497 declineProcceed = false;
498 } else {
499 console.tag('БОТ').error('Ошибка при принÑтии трейда #' + offer.offerid)
500 .tag('БОТ').log(err);
501 declineProcceed = false;
502 }
503 });
504}
505
506var queueProceed = function () {
507 redisClient.llen(redisChannels.checkList, function (err, length) {
508 if (length > 0 && !checkProcceed) {
509 console.tag('БОТ', 'Проверка').info('Проверка трейдов:' + length);
510 checkProcceed = true;
511 checkOfferPrice();
512 }
513 });
514 redisClient.llen(redisChannels.checkedList, function (err, length) {
515 if (length > 0 && !checkedProcceed && WebSession) {
516 console.tag('БОТ', 'Проверка').info('Проверено трейдов:' + length);
517 checkedProcceed = true;
518 redisClient.lindex(redisChannels.checkedList, 0, function (err, offer) {
519 checkedOffersProcceed(offer);
520 });
521 }
522 });
523 redisClient.llen(redisChannels.declineList, function (err, length) {
524 if (length > 0 && !declineProcceed && WebSession) {
525 console.tag('БОТ', 'Проверка').info('Отклонено трейдов:' + length);
526 declineProcceed = true;
527 redisClient.lindex(redisChannels.declineList, 0, function (err, offer) {
528 declineOffersProcceed(offer);
529 });
530 }
531 });
532 redisClient.llen(redisChannels.betsList, function (err, length) {
533 if (length > 0 && !betsProcceed && !delayForNewGame) {
534 console.tag('БОТ', 'Проверка').info('Ставок:' + length);
535 betsProcceed = true;
536 checkNewBet();
537 }
538 });
539 redisClient.llen(redisChannels.sendOffersList, function (err, length) {
540 if (length > 0 && !sendProcceed && WebSession) {
541 console.tag('БОТ', 'Проверка').info('Отправка трейда победителю:' + length);
542 sendProcceed = true;
543 redisClient.lindex(redisChannels.sendOffersList, 0, function (err, offerJson) {
544 offer = JSON.parse(offerJson);
545 sendTradeOffer(offer.appId, offer.steamid, offer.accessToken, offer.items, '', offer.game, offerJson);
546 });
547 }
548 });
549 redisClient.llen(redisChannels.checkItemsList, function (err, length) {
550 if (length > 0 && !parseItemsProcceed && WebSession) {
551 console.tag('БОТ', 'Проверка').info('ÐŸÐ°Ñ€Ñ Ð²ÐµÑ‰ÐµÐ¹:' + length);
552 parseItemsProcceed = true;
553 redisClient.lindex(redisChannels.checkItemsList, 0, function (err, offerJson) {
554 offer = JSON.parse(offerJson);
555 parseOffer(offer, offerJson);
556 });
557 }
558 });
559}
560var parseItemsProcceed = false;
561var checkProcceed = false;
562var checkedProcceed = false;
563var declineProcceed = false;
564var betsProcceed = false;
565var sendProcceed = false;
566var delayForNewGame = false;
567setInterval(queueProceed, 1500);
568
569module.exports.handleOffers = handleOffers;
570module.exports.delayForNewGame = function (value) {
571 delayForNewGame = value;
572};
573
574function getErrorCode(err, callback) {
575 var errCode = 0;
576 var match = err.match(/\(([^()]*)\)/);
577 if (match != null && match.length == 2) errCode = match[1];
578 callback(errCode);
579}