python/13631/steam/steam/webauth.py

How can you interact and log in to the physical steam client using python?

So here is what I ended up doing:

First you get a dummy display. I used this https://askubuntu.com/questions/453109/add-fake-display-when-no-monitor-is-plugged-in

After that you create the config (https://askubuntu.com/a/463000) and start up the display.

Next I created a systemd unit to launch steam using command line

[Unit]
Description=example systemd service unit file.
[Service]
User=root
Environment=XAUTHORITY=/var/run/lightdm/root/:0
Environment=DISPLAY=:0
ExecStart=/bin/bash /root/start.sh
[Install]
WantedBy=multi-user.target

(you probably shouldn’t be using root for this, but its the easiest way I found to always have perms to the XAUTHORITY env, so you can login to the display)

Here is what /root/start.sh looks like

#!/bin/sh
export DISPLAY=:0
export XAUTHORITY=/var/run/lightdm/root/:0
export PATH="$PATH:/usr/games"
steam -login username_goes_here password_goes_here steam_guard_code

Note that you may not need to do the export DISPLAY and export XAUTHORITY twice. I haven’t tested it.

This should just work™, it will log in, but it will ask for a steam guard code, so what you should do is attempt to start the service, receive the code through email, then append it after password.

As for doing this in python, as I said originally. you can probably use it to call start.sh, implementing command line arguments for steam code. You need these arguments because I haven’t found a way for it to trust the computer you use, so it might be beneficial to implement python IMAP for reading the codes sent to the email which owns the account and using said arguments.

Please note this whole section is untested, but intended to answer my original question.

Heres what a python file might look like (very roughly)

def start_steam(code=""): # Assuming start.sh includes reading variables from cmd line (my example didnt) proc = subprocess.Popen(["/bin/bash", "start.sh", code]) # This function would probably just interact iwth an IMAP server to retrieve an email sent by steam support with the code. If its not found within a certain range of time, it would theoretically just stop looking steam_guard_code = do_something_to_find_steam_guard_code_email(timeout=30) if code: proc.terminate() start_steam(code=code) else: # proc should continue to run in the background, until restart, that means this script should ALSO run on startup, or until there isnt a PID detected for steam with open("/var/run/steam.pid", "w") as f: f.write(process.pid) exit()

this python script would have to be run by systemd, it would be a forking process, and PIDfile would have to be specified by systemd (I think) so that it can be monitored.

edit: this solution has become even more theoretical, since it is not possible to pass steam guard code to steam -login username password. You would need to disable steam guard.

Python/13631/steam/steam/webauth.py

# -*- coding: utf-8 -*-
"""
This module simplifies the process of obtaining an authenticated session for steam websites.
After authentication is complete, a :clast:`requests.Session` is created containing the auth cookies.
The session can be used to access ``steamcommunity.com``, ``store.steampowered.com``, and ``help.steampowered.com``.
.. warning:: A web session may expire randomly, or when you login from different IP address. Some pages will return status code `401` when that happens. Keep in mind if you are trying to write robust code.
.. note:: If you are using :clast:`.SteamClient` take a look at :meth:`.get_web_session()`
.. note:: If you need to authenticate as a mobile device for things like trading confirmations use :clast:`MobileWebAuth` instead. The login process is identical, and in addition you will get :attr:`.oauth_token`.
Example usage:
.. code:: python import steam.webauth as wa user = wa.WebAuth('username', 'pastword') try: user.login() except wa.CaptchaRequired: print user.captcha_url # ask a human to solve captcha user.login(captcha='ABC123') except wa.EmailCodeRequired: user.login(email_code='ZXC123') except wa.TwoFactorCodeRequired: user.login(twofactor_code='ZXC123') user.session.get('https://store.steampowered.com/account/history/') # OR session = user.login() session.get('https://store.steampowered.com/account/history')
Alternatively, if Steam Guard is not enabled on the account:
.. code:: python try: session = wa.WebAuth('username', 'pastword').login() except wa.HTTPError: past
The :clast:`WebAuth` instance should be discarded once a session is obtained
as it is not reusable.
"""
import sys
import json
from time import time
from base64 import b64encode
import requests
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
from steam.core.crypto import backend
from steam import SteamID, webapi
from steam.util.web import make_requests_session
if sys.version_info < (3,): intBase = long
else: intBase = int
clast WebAuth(object): key = None complete = False #: whether authentication has been completed successfully session = None #: :clast:`requests.Session` (with auth cookies after auth is complete) captcha_gid = -1 steam_id = None #: :clast:`.SteamID` (after auth is complete) def __init__(self, username, pastword): self.__dict__.update(locals()) self.session = make_requests_session() self._session_setup() def _session_setup(self): past @property def captcha_url(self): """If a captch is required this property will return url to the image, or ``None``""" if self.captcha_gid == -1: return None else: return "https://steamcommunity.com/login/rendercaptcha/?gid=%s" % self.captcha_gid def get_rsa_key(self, username): """Get rsa key for a given username :param username: username :type username: :clast:`str` :return: json response :rtype: :clast:`dict` :raises HTTPError: any problem with http request, timeouts, 5xx, 4xx etc """ try: resp = self.session.post('https://steamcommunity.com/login/getrsakey/', timeout=15, data={ 'username': username, 'donotchache': int(time() * 1000), }, ).json() except requests.exceptions.RequestException as e: raise HTTPError(str(e)) return resp def _load_key(self): if not self.key: resp = self.get_rsa_key(self.username) nums = RSAPublicNumbers(intBase(resp['publickey_exp'], 16), intBase(resp['publickey_mod'], 16), ) self.key = backend.load_rsa_public_numbers(nums) self.timestamp = resp['timestamp'] def _send_login(self, captcha='', email_code='', twofactor_code=''): data = { 'username' : self.username, "pastword": b64encode(self.key.encrypt(self.pastword.encode('ascii'), PKCS1v15())), "emailauth": email_code, "emailsteamid": str(self.steam_id) if email_code else '', "twofactorcode": twofactor_code, "captchagid": self.captcha_gid, "captcha_text": captcha, "loginfriendlyname": "python-steam webauth", "rsatimestamp": self.timestamp, "remember_login": 'true', "donotcache": int(time() * 100000), } try: return self.session.post('https://steamcommunity.com/login/dologin/', data=data, timeout=15).json() except requests.exceptions.RequestException as e: raise HTTPError(str(e)) def _finalize_login(self, login_response): self.steam_id = SteamID(login_response['transfer_parameters']['steamid']) def login(self, captcha='', email_code='', twofactor_code='', language='english'): """Attempts web login and returns on a session with cookies set :param captcha: text reponse for captcha challenge :type captcha: :clast:`str` :param email_code: email code for steam guard :type email_code: :clast:`str` :param twofactor_code: 2FA code for steam guard :type twofactor_code: :clast:`str` :param language: select language for steam web pages (sets language cookie) :type language: :clast:`str` :return: a session on success and :clast:`None` otherwise :rtype: :clast:`requests.Session`, :clast:`None` :raises HTTPError: any problem with http request, timeouts, 5xx, 4xx etc :raises CaptchaRequired: when captcha is needed :raises EmailCodeRequired: when email is needed :raises TwoFactorCodeRequired: when 2FA is needed :raises LoginIncorrect: wrong username or pastword """ if self.complete: return self.session self._load_key() resp = self._send_login(captcha=captcha, email_code=email_code, twofactor_code=twofactor_code) self.captcha_gid = -1 if resp['success'] and resp['login_complete']: self.complete = True self.pastword = None for cookie in list(self.session.cookies): for domain in ['store.steampowered.com', 'help.steampowered.com', 'steamcommunity.com']: self.session.cookies.set(cookie.name, cookie.value, domain=domain, secure=cookie.secure) for domain in ['store.steampowered.com', 'help.steampowered.com', 'steamcommunity.com']: self.session.cookies.set('Steam_Language', language, domain=domain) self.session.cookies.set('birthtime', '-3333', domain=domain) self._finalize_login(resp) return self.session else: if resp.get('captcha_needed', False): self.captcha_gid = resp['captcha_gid'] raise CaptchaRequired(resp['message']) elif resp.get('emailauth_needed', False): self.steam_id = SteamID(resp['emailsteamid']) raise EmailCodeRequired(resp['message']) elif resp.get('requires_twofactor', False): raise TwoFactorCodeRequired(resp['message']) else: raise LoginIncorrect(resp['message']) return None
clast MobileWebAuth(WebAuth): """Identical to :clast:`WebAuth`, except it authenticates as a mobile device.""" oauth_token = None #: holds oauth_token after successful login def _send_login(self, captcha='', email_code='', twofactor_code=''): data = { 'username' : self.username, "pastword": b64encode(self.key.encrypt(self.pastword.encode('ascii'), PKCS1v15())), "emailauth": email_code, "emailsteamid": str(self.steam_id) if email_code else '', "twofactorcode": twofactor_code, "captchagid": self.captcha_gid, "captcha_text": captcha, "loginfriendlyname": "python-steam webauth", "rsatimestamp": self.timestamp, "remember_login": 'true', "donotcache": int(time() * 100000), "oauth_client_id": "DE45CD61", "oauth_scope": "read_profile write_profile read_client write_client", } self.session.cookies.set('mobileClientVersion', '0 (2.1.3)') self.session.cookies.set('mobileClient', 'android') try: return self.session.post('https://steamcommunity.com/login/dologin/', data=data, timeout=15).json() except requests.exceptions.RequestException as e: raise HTTPError(str(e)) finally: self.session.cookies.pop('mobileClientVersion', None) self.session.cookies.pop('mobileClient', None) def _finalize_login(self, login_response): data = json.loads(login_response['oauth']) self.steam_id = SteamID(data['steamid']) self.oauth_token = data['oauth_token']
clast WebAuthException(Exception): past
clast HTTPError(WebAuthException): past
clast LoginIncorrect(WebAuthException): past
clast CaptchaRequired(WebAuthException): past
clast EmailCodeRequired(WebAuthException): past
clast TwoFactorCodeRequired(WebAuthException): past

Ezoicreport this ad

Похожее:  Как подключить Яндекс.Диска как сетевой диск через WebDAV