Skip to content
63 changes: 46 additions & 17 deletions steampy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import urllib.parse as urlparse
from typing import List, Union
from decimal import Decimal
from urllib.parse import unquote

import requests

Expand Down Expand Up @@ -61,8 +62,8 @@ def __init__(
def set_proxies(self, proxies: dict) -> dict:
if not isinstance(proxies, dict):
raise TypeError(
'Proxy must be a dict. Example: '
'\{"http": "http://login:password@host:port"\, "https": "http://login:password@host:port"\}'
r'Proxy must be a dict. Example: '
r'\{"http": "http://login:password@host:port"\, "https": "http://login:password@host:port"\}'
)

if ping_proxy(proxies):
Expand All @@ -79,6 +80,17 @@ def set_login_cookies(self, cookies: dict) -> None:

self.market._set_login_executed(self.steam_guard, self._get_session_id())

steam_login_secure_cookies = [cookie for cookie in self._session.cookies if cookie.name == 'steamLoginSecure']
cookie_value = steam_login_secure_cookies[0].value
decoded_cookie_value = unquote(cookie_value)
access_token_parts = decoded_cookie_value.split('||')
if len(access_token_parts) < 2:
print(decoded_cookie_value)
raise ValueError('Access token not found in steamLoginSecure cookie')

access_token = access_token_parts[1]
self._access_token = access_token

@login_required
def get_steam_id(self) -> int:
url = SteamUrl.COMMUNITY_URL
Expand Down Expand Up @@ -152,18 +164,18 @@ def is_invalid_api_key(response: requests.Response) -> bool:
return msg in response.text

@login_required
def get_my_inventory(self, game: GameOptions, merge: bool = True, count: int = 5000) -> dict:
def get_my_inventory(self, game: GameOptions, merge: bool = True, count: int = 1000) -> dict:
steam_id = self.steam_guard['steamid']
return self.get_partner_inventory(steam_id, game, merge, count)

@login_required
def get_partner_inventory(
self, partner_steam_id: str, game: GameOptions, merge: bool = True, count: int = 5000
self, partner_steam_id: str, game: GameOptions, merge: bool = True, count: int = 1000
) -> dict:
url = '/'.join((SteamUrl.COMMUNITY_URL, 'inventory', partner_steam_id, game.app_id, game.context_id))
params = {'l': 'english', 'count': count}

response_dict = self._session.get(url, params=params).json()
response = (self._session.get(url, params=params))
response_dict = response.json()
if response_dict is None or response_dict.get('success') != 1:
raise ApiException('Success value should be 1.')

Expand All @@ -176,16 +188,23 @@ def get_trade_offers_summary(self) -> dict:
params = {'key': self._api_key}
return self.api_call('GET', 'IEconService', 'GetTradeOffersSummary', 'v1', params).json()

def get_trade_offers(self, merge: bool = True) -> dict:
def get_trade_offers(
self,
merge: bool = True,
use_webtoken: bool = True,
active_only: bool = True,
historical_only: bool = False,
time_historical_cutoff: str = ''
) -> dict:
params = {
'key': self._api_key,
'key'if not use_webtoken else 'access_token': self._api_key if not use_webtoken else self._access_token,
'get_sent_offers': 1,
'get_received_offers': 1,
'get_descriptions': 1,
'language': 'english',
'active_only': 1,
'historical_only': 0,
'time_historical_cutoff': '',
'active_only': 1 if active_only else 0,
'historical_only': 1 if historical_only else 0,
'time_historical_cutoff': time_historical_cutoff,
}
response = self.api_call('GET', 'IEconService', 'GetTradeOffers', 'v1', params).json()
response = self._filter_non_active_offers(response)
Expand All @@ -206,8 +225,11 @@ def _filter_non_active_offers(offers_response):

return offers_response

def get_trade_offer(self, trade_offer_id: str, merge: bool = True) -> dict:
params = {'key': self._api_key, 'tradeofferid': trade_offer_id, 'language': 'english'}
def get_trade_offer(self, trade_offer_id: str, merge: bool = True, use_webtoken: bool = True) -> dict:
params = {
'key'if not use_webtoken else 'access_token': self._api_key if not use_webtoken else self._access_token,
'tradeofferid': trade_offer_id, 'language': 'english'
}
response = self.api_call('GET', 'IEconService', 'GetTradeOffer', 'v1', params).json()

if merge and 'descriptions' in response['response']:
Expand Down Expand Up @@ -264,7 +286,6 @@ def accept_trade_offer(self, trade_offer_id: str) -> dict:
'captcha': '',
}
headers = {'Referer': self._get_trade_offer_url(trade_offer_id)}

response = self._session.post(accept_url, data=params, headers=headers).json()
if response.get('needs_mobile_confirmation', False):
return self._confirm_transaction(trade_offer_id)
Expand Down Expand Up @@ -367,6 +388,7 @@ def make_offer_with_url(
trade_offer_url: str,
message: str = '',
case_sensitive: bool = True,
confirm_trade: bool = True,
) -> dict:
token = get_key_value_from_url(trade_offer_url, 'token', case_sensitive)
partner_account_id = get_key_value_from_url(trade_offer_url, 'partner', case_sensitive)
Expand All @@ -390,9 +412,9 @@ def make_offer_with_url(
'Referer': f'{SteamUrl.COMMUNITY_URL}{urlparse.urlparse(trade_offer_url).path}',
'Origin': SteamUrl.COMMUNITY_URL,
}

response = self._session.post(url, data=params, headers=headers).json()
if response.get('needs_mobile_confirmation'):

if confirm_trade and response.get('needs_mobile_confirmation'):
response.update(self._confirm_transaction(response['tradeofferid']))

return response
Expand All @@ -403,7 +425,12 @@ def _get_trade_offer_url(trade_offer_id: str) -> str:

@login_required
# If convert_to_decimal = False, the price will be returned WITHOUT a decimal point.
def get_wallet_balance(self, convert_to_decimal: bool = True, on_hold: bool = False) -> Union[str, Decimal]:
def get_wallet_balance(
self,
convert_to_decimal: bool = True,
on_hold: bool = False,
return_full : bool = False
) -> Union[str, Decimal, dict]:
response = self._session.get(f'{SteamUrl.COMMUNITY_URL}/market')
wallet_info_match = re.search(r'var g_rgWalletInfo = (.*?);', response.text)
if wallet_info_match:
Expand All @@ -412,6 +439,8 @@ def get_wallet_balance(self, convert_to_decimal: bool = True, on_hold: bool = Fa
else:
raise Exception('Unable to get wallet balance string match')
balance_dict_key = 'wallet_delayed_balance' if on_hold else 'wallet_balance'
if return_full:
return balance_dict
if convert_to_decimal:
return Decimal(balance_dict[balance_dict_key]) / 100
else:
Expand Down
16 changes: 14 additions & 2 deletions steampy/confirmation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@


class Confirmation:
def __init__(self, data_confid, nonce):
def __init__(self, data_confid, nonce, creator_id):
self.data_confid = data_confid
self.nonce = nonce
self.creator_id = creator_id


class Tag(enum.Enum):
Expand Down Expand Up @@ -43,6 +44,16 @@ def confirm_sell_listing(self, asset_id: str) -> dict:
confirmation = self._select_sell_listing_confirmation(confirmations, asset_id)
return self._send_confirmation(confirmation)

def confirm_by_id(self, confirmation_id: str) -> bool:
# Confirm a trade/order based on confirmation_id
confirmations = self._get_confirmations()
for conf in confirmations:
if str(conf.creator_id) == str(confirmation_id):
result = self._send_confirmation(conf)
print(f'confirm_by_id result:{result}')
return result.get("success", False)
return False

def _send_confirmation(self, confirmation: Confirmation) -> dict:
tag = Tag.ALLOW
params = self._create_confirmation_params(tag.value)
Expand All @@ -60,7 +71,8 @@ def _get_confirmations(self) -> List[Confirmation]:
for conf in confirmations_json['conf']:
data_confid = conf['id']
nonce = conf['nonce']
confirmations.append(Confirmation(data_confid, nonce))
creator_id = conf['creator_id']
confirmations.append(Confirmation(data_confid, nonce, creator_id))
return confirmations
else:
raise ConfirmationExpected
Expand Down
15 changes: 14 additions & 1 deletion steampy/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from rsa import encrypt, PublicKey
from requests import Session, Response
from urllib.parse import unquote

from steampy import guard
from steampy.models import SteamUrl
Expand Down Expand Up @@ -41,6 +42,17 @@ def login(self) -> Session:
self.set_sessionid_cookies()
return self.session

steam_login_secure_cookies = [cookie for cookie in self._session.cookies if cookie.name == 'steamLoginSecure']
cookie_value = steam_login_secure_cookies[0].value
decoded_cookie_value = unquote(cookie_value)
access_token_parts = decoded_cookie_value.split('||')
if len(access_token_parts) < 2:
print(decoded_cookie_value)
raise ValueError('Access token not found in steamLoginSecure cookie')

access_token = access_token_parts[1]
self._access_token = access_token

def _send_login_request(self) -> Response:
rsa_params = self._fetch_rsa_params()
encrypted_password = self._encrypt_password(rsa_params)
Expand Down Expand Up @@ -137,5 +149,6 @@ def _finalize_login(self) -> Response:
sessionid = self.session.cookies['sessionid']
redir = f'{SteamUrl.COMMUNITY_URL}/login/home/?goto='
finalized_data = {'nonce': self.refresh_token, 'sessionid': sessionid, 'redir': redir}
response = self.session.post(SteamUrl.LOGIN_URL + '/jwt/finalizelogin', data=finalized_data)
headers = {'Referer': f'{SteamUrl.COMMUNITY_URL}/', 'Origin': SteamUrl.COMMUNITY_URL}
response = self.session.post(SteamUrl.LOGIN_URL + '/jwt/finalizelogin', data=finalized_data, headers=headers)
return response
Loading