· 9 years ago · Oct 08, 2016, 10:22 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 sendShopList: 'send.shop.list'
53}
54
55function steamBotLogger(log) {
56 console.tag('БОТ').log(log);
57}
58
59function EscrowLogger(log) {
60 console.tag('Ğ•ÑÂкроу Бот').info(log);
61}
62
63function generatekey(secret) {
64 code = SteamTotp.generateAuthCode(secret);
65 EscrowLogger('Сгенерированный код : ' + code);
66 return code;
67}
68
69steamClient.connect();
70steamClient.on('debug', steamBotLogger);
71steamClient.on('connected', function () {
72 steamUser.logOn(details);
73});
74
75steamClient.on('logOnResponse', function (logonResp) {
76 if (logonResp.eresult === Steam.EResult.OK) {
77 steamBotLogger('ЗалогинилÑÂÑÂ!');
78 steamFriends.setPersonaState(Steam.EPersonaState.Online);
79
80 steamWebLogOn.webLogOn(function (sessionID, newCookie) {
81 getSteamAPIKey({
82 sessionID: sessionID,
83 webCookie: newCookie
84 }, function (err, APIKey) {
85 offers.setup({
86 sessionID: sessionID,
87 webCookie: newCookie,
88 APIKey: APIKey
89 }, function (err) {
90 WebSession = true;
91 globalSession = sessionID;
92 WebCookies = newCookie;
93 redisClient.lrange(redisChannels.tradeoffersList, 0, -1, function (err, offers) {
94 offers.forEach(function (offer) {
95 checkingOffers.push(offer);
96 });
97 handleOffers();
98 AcceptMobileOffer();
99 });
100 steamBotLogger('ÄžÂаÑÂтройка трейдов!');
101 });
102
103 });
104 });
105 }
106});
107
108function handleOffers() {
109 offers.getOffers({
110 get_received_offers: 1,
111 active_only: 1
112 }, function (error, body) {
113 if (
114 body
115 && body.response
116 && body.response.trade_offers_received
117 ) {
118 body.response.trade_offers_received.forEach(function (offer) {
119 if (offer.trade_offer_state == 2) {
120 if (is_checkingOfferExists(offer.tradeofferid)) return;
121
122 if (offer.items_to_give != null && config.admins.indexOf(offer.steamid_other) != -1) {
123 console.tag('БОТ', 'Трейд').log('Трейд #' + offer.tradeofferid + ' От: ÄžÂÄžâ€ÄžÅ“ИĞÂĞ ' + offer.steamid_other);
124 offers.acceptOffer({tradeOfferId: offer.tradeofferid});
125 return;
126 }
127 if (offer.items_to_give != null) {
128 offers.declineOffer({tradeOfferId: offer.tradeofferid});
129 return;
130 }
131 offers.getTradeHoldDuration({tradeOfferId: offer.tradeofferid}, function (err, response) {
132 if (err) {
133 steamBotLogger('Отклонение. ÄžÂету ESCROW: ' + err);
134 offers.declineOffer({tradeOfferId: offer.tradeofferid});
135 steamBotLogger('Отклонение. ÄžÂету ESCROW: ' + offer.tradeofferid);
136 return;
137 } else if (response.their != 0) {
138 steamBotLogger('response.their: ' + response.their);
139 offers.declineOffer({tradeOfferId: offer.tradeofferid});
140 steamBotLogger('Отклонение. ÄžÂету ESCROW: ' + offer.tradeofferid);
141 return;
142 }
143 });
144 if (offer.items_to_receive != null && offer.items_to_give == null) {
145 checkingOffers.push(offer.tradeofferid);
146 console.tag('БОТ', 'Трейдофферы').log('Трейд #' + offer.tradeofferid + ' От: ' + offer.steamid_other);
147 redisClient.multi([
148 ['rpush', redisChannels.tradeoffersList, offer.tradeofferid],
149 ['rpush', redisChannels.checkItemsList, JSON.stringify(offer)],
150 ['rpush', redisChannels.usersQueue, offer.steamid_other]
151 ]).exec(function () {
152 redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
153 io.sockets.emit('queue', queues);
154 });
155 });
156 return;
157 }
158 }
159 });
160 }
161 });
162}
163
164steamUser.on('tradeOffers', function (number) {
165 if (number > 0) {
166 handleOffers();
167 }
168});
169
170
171var parseOffer = function (offer, offerJson) {
172 offers.loadPartnerInventory({
173 partnerSteamId: offer.steamid_other,
174 appId: 730,
175 contextId: 2,
176 tradeOfferId: offer.tradeofferid,
177 language: "english"
178 }, function (err, hitems) {
179 if (err) {
180 redisClient.multi([
181 ['rpush', redisChannels.declineList, offer.tradeofferid],
182 ['lrem', redisChannels.checkItemsList, 0, offerJson],
183 ['lrem', redisChannels.usersQueue, 1, offer.steamid_other]
184 ])
185 .exec(function (err, replies) {
186 parseItemsProcceed = false;
187 return;
188 });
189 return;
190 }
191 var items = offer.items_to_receive;
192 var items_to_check = [], num = 0;
193 for (var i = 0; i < items.length; i++) {
194 for (var j = 0; j < hitems.length; j++) {
195 if (items[i].assetid == hitems[j].id) {
196 items_to_check[num] = {
197 appid: hitems[j].appid,
198 name: hitems[j].market_name,
199 market_hash_name: hitems[j].market_hash_name,
200 classid: hitems[j].classid
201 };
202 var type = hitems[j].type;
203 var rarity = '';
204 var arr = type.split(',');
205 if (arr.length == 2) type = arr[1].trim();
206 if (arr.length == 3) type = arr[2].trim();
207 if (arr.length && arr[0] == 'ÄžÂож') type = '★';
208 switch (type) {
209 case 'ÄžÂрмейÑÂкое качеÑÂтво':
210 rarity = 'milspec';
211 break;
212 case 'Запрещенное':
213 rarity = 'restricted';
214 break;
215 case 'ЗаÑÂекреченное':
216 rarity = 'classified';
217 break;
218 case 'Тайное':
219 rarity = 'covert';
220 break;
221 case 'Ширпотреб':
222 rarity = 'common';
223 break;
224 case 'Промышленное качеÑÂтво':
225 rarity = 'common';
226 break;
227 case '★':
228 rarity = 'rare';
229 break;
230 }
231 items_to_check[num].rarity = rarity;
232 num++;
233 break;
234 }
235 }
236 }
237 var value = {
238 offerid: offer.tradeofferid,
239 accountid: offer.steamid_other,
240 items: JSON.stringify(items_to_check)
241 };
242
243 console.tag('БОТ', 'Трейд #' + value.offerid).log(value);
244
245 redisClient.multi([
246 ['rpush', redisChannels.checkList, JSON.stringify(value)],
247 ['lrem', redisChannels.checkItemsList, 0, offerJson]
248 ])
249 .exec(function (err, replies) {
250 parseItemsProcceed = false;
251 });
252
253 });
254}
255
256var checkOfferPrice = function () {
257 requestify.post('http://' + config.domain + '/api/checkOffer', {
258 secretKey: config.secretKey
259 })
260 .then(function (response) {
261 var answer = JSON.parse(response.body);
262
263 if (answer.success) {
264 checkProcceed = false;
265 }
266 }, function (response) {
267 console.tag('БОТ').error('Something wrong with check offers. Retry...');
268 setTimeout(function () {
269 checkOfferPrice()
270 }, 1000);
271 });
272
273}
274
275var checkNewBet = function () {
276 requestify.post('http://' + config.domain + '/api/newBet', {
277 secretKey: config.secretKey
278 })
279 .then(function (response) {
280 var answer = JSON.parse(response.body);
281 if (answer.success) {
282 betsProcceed = false;
283 }
284 }, function (response) {
285 console.tag('БОТ').error('Something wrong with send a new bet. Retry...');
286 setTimeout(function () {
287 checkNewBet()
288 }, 1000);
289 });
290}
291
292var checkArrGlobal = [];
293
294
295var sendShopTradeOffer = function(appId, partnerSteamId, accessToken, sendItems, message, game, offerJson){
296 try {
297 offers.loadMyInventory({
298 appId: appId,
299 contextId: 2
300 }, function (err, items) {
301 if(err) {
302 console.log(err);
303 sendShopProcceed = false;
304 return;
305 }
306 var itemsFromMe = [],
307 checkArr = [],
308 num = 0;
309 var i = 0;
310 for (var i = 0; i < sendItems.length; i++) {
311 for (var j = 0; j < items.length; j++) {
312 if (items[j].tradable && (items[j].classid == sendItems[i])) {
313 if ((checkArr.indexOf(items[j].id) == -1) && (checkArrGlobal.indexOf(items[j].id) == -1)) {
314 checkArr[i] = items[j].id;
315 itemsFromMe[num] = {
316 appid: 730,
317 contextid: 2,
318 amount: items[j].amount,
319 assetid: items[j].id
320 };
321 num++;
322 break;
323 }
324 }
325 }
326 }
327 if (num > 0) {
328 offers.makeOffer({
329 partnerSteamId: partnerSteamId,
330 accessToken: accessToken,
331 itemsFromMe: itemsFromMe,
332 itemsFromThem: [],
333 message: 'Ваша покупка на ÑÂайте '+config.domain
334 }, function (err, response) {
335 if (err) {
336 console.tag('БОТ', 'Отправка выигрыша').error('Магазин: Ошибка отправки трейда:' + err.message);
337 getErrorCode(err.message, function(errCode){
338 if(errCode == 15) {
339 redisClient.lrem(redisChannels.sendShopList, 0, offerJson, function (err, data) {
340 sendShopProcceed = false;
341 });
342 sendShopProcceed = false;
343 }
344 sendProsendShopProcceedcceed = false;
345 });
346 return;
347 }
348 checkArrGlobal = checkArrGlobal.concat(checkArr);
349 console.log(checkArrGlobal);
350 console.log(checkArr);
351 redisClient.lrem(redisChannels.sendShopList, 0, offerJson, function(err, data){
352 sendShopProcceed = false;
353 });
354 console.tag('БОТ', 'Отправка выигрыша').log('Магазин: Трейд #' + response.tradeofferid +' Отправлен!');
355 AcceptMobileOffer();
356 });
357 }else{
358 console.tag('БОТ', 'Отправка приза').log('Магазин: Вещи не найдены!!');
359 redisClient.lrem(redisChannels.sendShopList, 0, offerJson, function(err, data){
360 sendShopProcceed = false;
361 });
362 }
363 });
364
365 }catch(ex){
366 console.tag('БОТ').error('Магазин: Ошибка отправки ÑÂтавки');
367 setPrizeStatus(game, 2);
368 sendShopProcceed = false;
369 }
370};
371
372var sendTradeOffer = function (appId, partnerSteamId, accessToken, sendItems, message, game, offerJson) {
373 try {
374 offers.loadMyInventory({
375 appId: appId,
376 contextId: 2
377 }, function (err, items) {
378 if (err) {
379 console.log(err);
380 sendProcceed = false;
381 return;
382 }
383 var itemsFromMe = [],
384 checkArr = [],
385 num = 0;
386 var i = 0;
387 for (var i = 0; i < sendItems.length; i++) {
388 for (var j = 0; j < items.length; j++) {
389 if (items[j].tradable && (items[j].classid == sendItems[i])) {
390 if ((checkArr.indexOf(items[j].id) == -1) && (checkArrGlobal.indexOf(items[j].id) == -1)) {
391 checkArr[i] = items[j].id;
392 itemsFromMe[num] = {
393 appid: 730,
394 contextid: 2,
395 amount: items[j].amount,
396 assetid: items[j].id
397 };
398 num++;
399 break;
400 }
401 }
402 }
403 }
404 if (num > 0) {
405 offers.makeOffer({
406 partnerSteamId: partnerSteamId,
407 accessToken: accessToken,
408 itemsFromMe: itemsFromMe,
409 itemsFromThem: [],
410 message: 'ПоздравлÑÂем Ѡпобедой на ÑÂайте ' + config.domain + ' | Ğ’ игре #' + game
411 }, function (err, response) {
412 if (err) {
413 console.tag('БОТ', 'Отправка выигрыша').error('Ошибка отправки выигрыша:' + err.message);
414 getErrorCode(err.message, function (errCode) {
415 if (errCode == 15 || errCode == 25 || err.message.indexOf('Ошибка отправки вашего трейда. Попробуйте позже!')) {
416 redisClient.lrem(redisChannels.sendOffersList, 0, offerJson, function (err, data) {
417 setPrizeStatus(game, 2);
418 sendProcceed = false;
419 });
420 sendProcceed = false;
421 }
422 sendProcceed = false;
423 });
424 return;
425 }
426 checkArrGlobal = checkArrGlobal.concat(checkArr);
427 redisClient.lrem(redisChannels.sendOffersList, 0, offerJson, function (err, data) {
428 setPrizeStatus(game, 1);
429 sendProcceed = false;
430 });
431 console.tag('БОТ', 'Отправка выигрыша').log('Трейд #' + response.tradeofferid + ' отправлен!');
432 AcceptMobileOffer();
433 });
434 } else {
435 console.tag('БОТ', 'Отправка выигрыша').log('Вещи не найдены!');
436 redisClient.lrem(redisChannels.sendOffersList, 0, offerJson, function (err, data) {
437 setPrizeStatus(game, 1);
438 sendProcceed = false;
439 });
440 }
441 });
442
443 } catch (ex) {
444 console.tag('БОТ').error('Ошибка отправки выигрыша');
445 setPrizeStatus(game, 2);
446 sendProcceed = false;
447 }
448};
449
450var setPrizeStatus = function (game, status) {
451 requestify.post('http://' + config.domain + '/api/setPrizeStatus', {
452 secretKey: config.secretKey,
453 game: game,
454 status: status
455 })
456 .then(function (response) {
457
458 }, function (response) {
459 console.tag('БОТ').log('Ошибка Ñ ÑÂтатуÑÂом приза. Перепробываем...');
460 setTimeout(function () {
461 setPrizeStatus()
462 }, 1000);
463 });
464}
465
466var is_checkingOfferExists = function (tradeofferid) {
467 for (var i = 0, len = checkingOffers.length; i < len; ++i) {
468 var offer = checkingOffers[i];
469 if (offer == tradeofferid) {
470 return true;
471 break;
472 }
473 }
474 return false;
475}
476
477var checkedOffersProcceed = function (offerJson) {
478 var offer = JSON.parse(offerJson);
479 if (offer.success) {
480 console.tag('БОТ').log('ПроцеÑÂѠпринÑÂтиѠтрейда: #' + offer.offerid);
481 offers.acceptOffer({tradeOfferId: offer.offerid}, function (err, body) {
482 if (!err) {
483 redisClient.multi([
484 ["lrem", redisChannels.tradeoffersList, 0, offer.offerid],
485 ["lrem", redisChannels.usersQueue, 1, offer.steamid64],
486 ["rpush", redisChannels.betsList, offerJson],
487 ["lrem", redisChannels.checkedList, 0, offerJson]
488 ])
489 .exec(function (err, replies) {
490 redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
491 io.sockets.emit('queue', queues);
492 console.tag('БОТ').log("Ставка принÑÂта!");
493 checkedProcceed = false;
494 });
495 });
496 AcceptMobileOffer();
497 } else {
498 console.tag('БОТ').error('Ошибка при принÑÂтии трейда #' + offer.offerid)
499 .tag('БОТ').log(err);
500
501 offers.getOffer({tradeOfferId: offer.offerid}, function (err, body) {
502 if (body.response.offer) {
503 var offerCheck = body.response.offer;
504 if (offerCheck.trade_offer_state == 2) {
505 checkedProcceed = false;
506 return;
507 }
508 if (offerCheck.trade_offer_state == 3) {
509 redisClient.multi([
510 ["lrem", redisChannels.tradeoffersList, 0, offer.offerid],
511 ["lrem", redisChannels.usersQueue, 1, offer.steamid64],
512 ["rpush", redisChannels.betsList, offerJson],
513 ["lrem", redisChannels.checkedList, 0, offerJson]
514 ])
515 .exec(function (err, replies) {
516 redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
517 io.sockets.emit('queue', queues);
518 checkedProcceed = false;
519 });
520 });
521 } else {
522 redisClient.multi([
523 ["lrem", redisChannels.tradeoffersList, 0, offer.offerid],
524 ["lrem", redisChannels.usersQueue, 1, offer.steamid64],
525 ["lrem", redisChannels.checkedList, 0, offerJson]
526 ])
527 .exec(function (err, replies) {
528 redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
529 io.sockets.emit('queue', queues);
530 checkedProcceed = false;
531 });
532 });
533 }
534 }
535 })
536 }
537 });
538 }
539}
540
541function AcceptMobileOffer() {
542 // ИнформациѠдлѠмобильных подтверждений
543 var steamcommunityMobileConfirmations = new SteamcommunityMobileConfirmations(
544 {
545 steamid: config.bot.steamid,
546 identity_secret: config.bot.identity_secret,
547 device_id: device_id,
548 webCookie: WebCookies,
549 });
550
551 steamcommunityMobileConfirmations.FetchConfirmations((function (err, confirmations) {
552 if (err) {
553 console.log(err);
554 return;
555 }
556 console.tag('БОТ', 'Мобильное подтверждение').log('Трейдов в ожидании: ' + confirmations.length);
557 if (!confirmations.length) {
558 return;
559 }
560 steamcommunityMobileConfirmations.AcceptConfirmation(confirmations[0], (function (err, result) {
561 if (err) {
562 console.log(err);
563 return;
564 }
565 console.tag('БОТ', 'Мобильное подтверждение').log('Результат: ' + result);
566 }).bind(this));
567 }).bind(this));
568}
569
570var declineOffersProcceed = function (offerid) {
571 console.tag('БОТ').log('ПроцеÑÂѠотклонениÑÂ: #' + offerid);
572 offers.declineOffer({tradeOfferId: offerid}, function (err, body) {
573 if (!err) {
574 console.tag('БОТ').log('Трейд #' + offerid + ' Отклонен!');
575 redisClient.lrem(redisChannels.declineList, 0, offerid);
576 declineProcceed = false;
577 } else {
578 console.tag('БОТ').error('Ошибка при принÑÂтии трейда #' + offer.offerid)
579 .tag('БОТ').log(err);
580 declineProcceed = false;
581 }
582 });
583}
584
585var queueProceed = function () {
586 redisClient.llen(redisChannels.checkList, function (err, length) {
587 if (length > 0 && !checkProcceed) {
588 console.tag('БОТ', 'Проверка').info('Проверка трейдов:' + length);
589 checkProcceed = true;
590 checkOfferPrice();
591 }
592 });
593 redisClient.llen(redisChannels.checkedList, function (err, length) {
594 if (length > 0 && !checkedProcceed && WebSession) {
595 console.tag('БОТ', 'Проверка').info('Проверено трейдов:' + length);
596 checkedProcceed = true;
597 redisClient.lindex(redisChannels.checkedList, 0, function (err, offer) {
598 checkedOffersProcceed(offer);
599 });
600 }
601 });
602 redisClient.llen(redisChannels.declineList, function (err, length) {
603 if (length > 0 && !declineProcceed && WebSession) {
604 console.tag('БОТ', 'Проверка').info('Отклонено трейдов:' + length);
605 declineProcceed = true;
606 redisClient.lindex(redisChannels.declineList, 0, function (err, offer) {
607 declineOffersProcceed(offer);
608 });
609 }
610 });
611 redisClient.llen(redisChannels.betsList, function (err, length) {
612 if (length > 0 && !betsProcceed && !delayForNewGame) {
613 console.tag('БОТ', 'Проверка').info('Ставок:' + length);
614 betsProcceed = true;
615 checkNewBet();
616 }
617 });
618 redisClient.llen(redisChannels.sendOffersList, function (err, length) {
619 if (length > 0 && !sendProcceed && WebSession) {
620 console.tag('БОТ', 'Проверка').info('Отправка трейда победителю:' + length);
621 sendProcceed = true;
622 redisClient.lindex(redisChannels.sendOffersList, 0, function (err, offerJson) {
623 offer = JSON.parse(offerJson);
624 sendTradeOffer(offer.appId, offer.steamid, offer.accessToken, offer.items, '', offer.game, offerJson);
625 });
626 }
627 });
628 redisClient.llen(redisChannels.sendShopList, function(err, length) {
629 if (length > 0 && !sendShopProcceed && WebSession) {
630 console.tag('Магазин','Проверка').info('Отправка вещей из магазина:' + length);
631 sendShopProcceed = true;
632 redisClient.lindex(redisChannels.sendShopList, 0,function (err, offerJson) {
633 offer = JSON.parse(offerJson);
634 sendShopTradeOffer(offer.appId, offer.steamid, offer.accessToken, offer.items, '', offer.game, offerJson);
635 });
636 }
637 });
638 redisClient.llen(redisChannels.checkItemsList, function (err, length) {
639 if (length > 0 && !parseItemsProcceed && WebSession) {
640 console.tag('БОТ', 'Проверка').info('ПарѠвещей:' + length);
641 parseItemsProcceed = true;
642 redisClient.lindex(redisChannels.checkItemsList, 0, function (err, offerJson) {
643 offer = JSON.parse(offerJson);
644 parseOffer(offer, offerJson);
645 });
646 }
647 });
648}
649var parseItemsProcceed = false;
650var checkProcceed = false;
651var checkedProcceed = false;
652var declineProcceed = false;
653var betsProcceed = false;
654var sendProcceed = false;
655var delayForNewGame = false;
656var sendShopProcceed = false;
657setInterval(queueProceed, 1500);
658
659module.exports.handleOffers = handleOffers;
660module.exports.delayForNewGame = function (value) {
661 delayForNewGame = value;
662};
663
664function getErrorCode(err, callback) {
665 var errCode = 0;
666 var match = err.match(/\(([^()]*)\)/);
667 if (match != null && match.length == 2) errCode = match[1];
668 callback(errCode);
669}