# frozen_string_literal: true module Steam module Handler # Handles messages releated to a Steam user # # @example Logging in # steam_user = client.steam_user # steam_user.login(username, password, token, hash) # # @note You need to handle the LogonResponse to catch Steam Guard prompts # and 2FA class SteamUser include Handler::Base handles EMsg::CLIENT_LOG_ON_RESPONSE, EMsg::CLIENT_UPDATE_MACHINE_AUTH, EMsg::CLIENT_LOGGED_OFF, EMsg::CLIENT_NEW_LOGIN_KEY # rubocop:disable MethodLength # rubocop:disable AbcSize # # Log a Client in # # @param username [String] the username # @param password [String] the password # @param token [String] the SteamGuard token or nil # @param hash [String] the SteamGuard hash or nil # # @return True or false if the message was sent. You must handle the # ClientLogonResponse to know the real logon result def login(username, password, token = nil, hash = nil) msg = ProtobufMessage.new(MsgHdrProtoBuf.new, Steamclient::CMsgClientLogon.new, EMsg::CLIENT_LOGON) msg.body.auth_code = token if token msg.body.eresult_sentryfile = EResult::FILE_NOT_FOUND if hash msg.body.sha_sentryfile = hash msg.body.eresult_sentryfile = EResult::OK end ip = LocalIp.new.to_i ^ MsgClientLogon::OBFUSCATION_MASK msg.body.obfustucated_private_ip = ip msg.body.account_name = username msg.body.password = password msg.body.protocol_version = MsgClientLogon::CURRENT_PROTOCOL msg.body.client_os_type = EOSType::WIN311 msg.body.client_package_version = 1771 send_msg(msg) end # Change the Client's persona state. # # @example Setting a Client as "Online" # steam_user = client.steam_user # steam_user.change_persona_state(EPersonaState::ONLINE) # # @param state [EMsg::E_PERSONA_STATE] the new client state # @return True if the message was sent, false otherwise def change_persona_state(state) client_status = Steamclient::CMsgClientChangeStatus.new client_status.persona_state = state client_change_status = ProtobufMessage.new(MsgHdrProtoBuf.new, client_status, EMsg::CLIENT_CHANGE_STATUS) send_msg(client_change_status) end # Change the Client's name # # @example Setting a Client as "Jimbo" # steam_user = client.steam_user # steam_user.change_persona_name("Jimbo") # # @param name [String] the new client name # @return True if the message was sent, false otherwise def change_persona_name(name) client_status = Steamclient::CMsgClientChangeStatus.new client_status.player_name = name client_change_status = ProtobufMessage.new(MsgHdrProtoBuf.new, client_status, EMsg::CLIENT_CHANGE_STATUS) send_msg(client_change_status) end # Logs the Client off the Steam network # # @return [Bool] def logoff logoff = ProtobufMessage.new(MsgHdrProtoBuf.new, Steamclient::CMsgClientLogOff.new, EMsg::CLIENT_LOG_OFF) send_msg(logoff) end # Handles a given packet # # @param packet [Networking::Packet] the packet to handle def handle(packet) case packet.msg_type when EMsg::CLIENT_LOG_ON_RESPONSE handle_client_logon_response(packet) when EMsg::CLIENT_UPDATE_MACHINE_AUTH handle_machine_auth_update(packet) when EMsg::CLIENT_NEW_LOGIN_KEY handle_login_key(packet) when EMsg::CLIENT_LOGGED_OFF handle_client_logoff(packet) end end private # @api private def handle_client_logoff(packet) msg = packet.as_message(Steamclient::CMsgClientLoggedOff.new) raise NotImplementedError, msg.inspect.to_s end # @api private def handle_login_key(packet) msg = packet.as_message(Steamclient::CMsgClientNewLoginKey.new) resp = Steamclient::CMsgClientNewLoginKeyAccepted.new resp.unique_id = msg.body.unique_id resp = ProtobufMessage.new(MsgHdrProtoBuf.new, resp, EMsg::CLIENT_NEW_LOGIN_KEY_ACCEPTED) send_msg(resp) end # @api private def handle_machine_auth_update(packet) msg = packet.as_message(Steamclient::CMsgClientUpdateMachineAuth.new) digest = Digest::SHA1.digest(msg.body.bytes) resp = Steamclient::CMsgClientUpdateMachineAuthResponse.new resp.sha_file = digest file = SentryFile.new file.write(digest) header = MsgHdrProtoBuf.new header.proto.jobid_target = msg.header.proto.jobid_source resp = ProtobufMessage.new(header, resp, EMsg::CLIENT_UPDATE_MACHINE_AUTH_RESPONSE) send_msg(resp) end # @api private def handle_client_logon_response(packet) resp = packet.as_message(Steamclient::CMsgClientLogonResponse.new) body = resp.body proto = resp.header.proto if body.eresult == EResult::OK && proto.client_sessionid.positive? client.create_session(proto.steamid, proto.client_sessionid) client.start_heartbeat(body.out_of_game_heartbeat_seconds) end client.on_logon(resp) end end end end