use super::*;
use crate::networking_types::NetworkingIdentity;
#[cfg(test)]
use serial_test::serial;
pub struct User<Manager> {
pub(crate) user: *mut sys::ISteamUser,
pub(crate) _inner: Arc<Inner<Manager>>,
}
impl<Manager> User<Manager> {
pub fn steam_id(&self) -> SteamId {
unsafe { SteamId(sys::SteamAPI_ISteamUser_GetSteamID(self.user)) }
}
pub fn level(&self) -> u32 {
unsafe { sys::SteamAPI_ISteamUser_GetPlayerSteamLevel(self.user) as u32 }
}
pub fn logged_on(&self) -> bool {
unsafe { sys::SteamAPI_ISteamUser_BLoggedOn(self.user) }
}
pub fn authentication_session_ticket_with_steam_id(
&self,
steam_id: SteamId,
) -> (AuthTicket, Vec<u8>) {
self.authentication_session_ticket(NetworkingIdentity::new_steam_id(steam_id))
}
pub fn authentication_session_ticket(
&self,
network_identity: NetworkingIdentity,
) -> (AuthTicket, Vec<u8>) {
unsafe {
let mut ticket = vec![0; 1024];
let mut ticket_len = 0;
let auth_ticket = sys::SteamAPI_ISteamUser_GetAuthSessionTicket(
self.user,
ticket.as_mut_ptr() as *mut _,
1024,
&mut ticket_len,
network_identity.as_ptr(),
);
ticket.truncate(ticket_len as usize);
(AuthTicket(auth_ticket), ticket)
}
}
pub fn cancel_authentication_ticket(&self, ticket: AuthTicket) {
unsafe {
sys::SteamAPI_ISteamUser_CancelAuthTicket(self.user, ticket.0);
}
}
pub fn begin_authentication_session(
&self,
user: SteamId,
ticket: &[u8],
) -> Result<(), AuthSessionError> {
unsafe {
let res = sys::SteamAPI_ISteamUser_BeginAuthSession(
self.user,
ticket.as_ptr() as *const _,
ticket.len() as _,
user.0,
);
Err(match res {
sys::EBeginAuthSessionResult::k_EBeginAuthSessionResultOK => return Ok(()),
sys::EBeginAuthSessionResult::k_EBeginAuthSessionResultInvalidTicket => {
AuthSessionError::InvalidTicket
}
sys::EBeginAuthSessionResult::k_EBeginAuthSessionResultDuplicateRequest => {
AuthSessionError::DuplicateRequest
}
sys::EBeginAuthSessionResult::k_EBeginAuthSessionResultInvalidVersion => {
AuthSessionError::InvalidVersion
}
sys::EBeginAuthSessionResult::k_EBeginAuthSessionResultGameMismatch => {
AuthSessionError::GameMismatch
}
sys::EBeginAuthSessionResult::k_EBeginAuthSessionResultExpiredTicket => {
AuthSessionError::ExpiredTicket
}
_ => unreachable!(),
})
}
}
pub fn end_authentication_session(&self, user: SteamId) {
unsafe {
sys::SteamAPI_ISteamUser_EndAuthSession(self.user, user.0);
}
}
pub fn authentication_session_ticket_for_webapi(&self, identity: &str) -> AuthTicket {
unsafe {
let c_str = CString::new(identity).unwrap();
let c_world: *const ::std::os::raw::c_char =
c_str.as_ptr() as *const ::std::os::raw::c_char;
let auth_ticket = sys::SteamAPI_ISteamUser_GetAuthTicketForWebApi(self.user, c_world);
AuthTicket(auth_ticket)
}
}
}
#[derive(Debug, Error)]
pub enum AuthSessionError {
#[error("invalid ticket")]
InvalidTicket,
#[error("duplicate ticket request")]
DuplicateRequest,
#[error("incompatible interface version")]
InvalidVersion,
#[error("incorrect game for ticket")]
GameMismatch,
#[error("ticket has expired")]
ExpiredTicket,
}
#[test]
#[serial]
fn test_auth_dll() {
let (client, single) = Client::init().unwrap();
let user = client.user();
let _cb = client.register_callback(|v: AuthSessionTicketResponse| {
println!("Got dll auth response: {:?}", v)
});
let _cb = client.register_callback(|v: ValidateAuthTicketResponse| {
println!("Got validate auth reponse: {:?}", v)
});
let id = user.steam_id();
let (auth, ticket) = user.authentication_session_ticket_with_steam_id(id);
println!("{:?}", auth);
println!("{:?}", ticket);
println!("{:?}", user.begin_authentication_session(id, &ticket));
for _ in 0..20 {
single.run_callbacks();
::std::thread::sleep(::std::time::Duration::from_millis(50));
}
println!("END");
user.cancel_authentication_ticket(auth);
for _ in 0..20 {
single.run_callbacks();
::std::thread::sleep(::std::time::Duration::from_millis(50));
}
user.end_authentication_session(id);
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AuthTicket(pub(crate) sys::HAuthTicket);
#[derive(Clone, Debug)]
pub struct AuthSessionTicketResponse {
pub ticket: AuthTicket,
pub result: SResult<()>,
}
unsafe impl Callback for AuthSessionTicketResponse {
const ID: i32 = 163;
const SIZE: i32 = ::std::mem::size_of::<sys::GetAuthSessionTicketResponse_t>() as i32;
unsafe fn from_raw(raw: *mut c_void) -> Self {
let val = &mut *(raw as *mut sys::GetAuthSessionTicketResponse_t);
AuthSessionTicketResponse {
ticket: AuthTicket(val.m_hAuthTicket),
result: if val.m_eResult == sys::EResult::k_EResultOK {
Ok(())
} else {
Err(val.m_eResult.into())
},
}
}
}
#[test]
#[serial]
fn test_auth_webapi() {
let (client, single) = Client::init().unwrap();
let user = client.user();
let _cb = client.register_callback(|v: TicketForWebApiResponse| {
println!("Got webapi auth response: {:?}", v)
});
let auth = user.authentication_session_ticket_for_webapi("myIdentity");
println!("{:?}", auth);
for _ in 0..20 {
single.run_callbacks();
::std::thread::sleep(::std::time::Duration::from_millis(100));
}
println!("END");
}
#[derive(Debug)]
pub struct TicketForWebApiResponse {
pub ticket_handle: AuthTicket,
pub result: SResult<()>,
pub ticket_len: i32,
pub ticket: Vec<u8>,
}
unsafe impl Callback for TicketForWebApiResponse {
const ID: i32 = 168;
const SIZE: i32 = ::std::mem::size_of::<sys::GetTicketForWebApiResponse_t>() as i32;
unsafe fn from_raw(raw: *mut c_void) -> Self {
println!("From raw: {:?}", raw);
let val = &mut *(raw as *mut sys::GetTicketForWebApiResponse_t);
TicketForWebApiResponse {
ticket_handle: AuthTicket(val.m_hAuthTicket),
result: if val.m_eResult == sys::EResult::k_EResultOK {
Ok(())
} else {
Err(val.m_eResult.into())
},
ticket_len: val.m_cubTicket,
ticket: val.m_rgubTicket.to_vec(),
}
}
}
#[derive(Clone, Debug)]
pub struct ValidateAuthTicketResponse {
pub steam_id: SteamId,
pub response: Result<(), AuthSessionValidateError>,
pub owner_steam_id: SteamId,
}
unsafe impl Callback for ValidateAuthTicketResponse {
const ID: i32 = 143;
const SIZE: i32 = ::std::mem::size_of::<sys::ValidateAuthTicketResponse_t>() as i32;
unsafe fn from_raw(raw: *mut c_void) -> Self {
let val = &mut *(raw as *mut sys::ValidateAuthTicketResponse_t);
ValidateAuthTicketResponse {
steam_id: SteamId(val.m_SteamID.m_steamid.m_unAll64Bits),
owner_steam_id: SteamId(val.m_OwnerSteamID.m_steamid.m_unAll64Bits),
response: match val.m_eAuthSessionResponse {
sys::EAuthSessionResponse::k_EAuthSessionResponseOK => Ok(()),
sys::EAuthSessionResponse::k_EAuthSessionResponseUserNotConnectedToSteam => {
Err(AuthSessionValidateError::UserNotConnectedToSteam)
}
sys::EAuthSessionResponse::k_EAuthSessionResponseNoLicenseOrExpired => {
Err(AuthSessionValidateError::NoLicenseOrExpired)
}
sys::EAuthSessionResponse::k_EAuthSessionResponseVACBanned => {
Err(AuthSessionValidateError::VACBanned)
}
sys::EAuthSessionResponse::k_EAuthSessionResponseLoggedInElseWhere => {
Err(AuthSessionValidateError::LoggedInElseWhere)
}
sys::EAuthSessionResponse::k_EAuthSessionResponseVACCheckTimedOut => {
Err(AuthSessionValidateError::VACCheckTimedOut)
}
sys::EAuthSessionResponse::k_EAuthSessionResponseAuthTicketCanceled => {
Err(AuthSessionValidateError::AuthTicketCancelled)
}
sys::EAuthSessionResponse::k_EAuthSessionResponseAuthTicketInvalidAlreadyUsed => {
Err(AuthSessionValidateError::AuthTicketInvalidAlreadyUsed)
}
sys::EAuthSessionResponse::k_EAuthSessionResponseAuthTicketInvalid => {
Err(AuthSessionValidateError::AuthTicketInvalid)
}
sys::EAuthSessionResponse::k_EAuthSessionResponsePublisherIssuedBan => {
Err(AuthSessionValidateError::PublisherIssuedBan)
}
_ => unreachable!(),
},
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MicroTxnAuthorizationResponse {
pub app_id: AppId,
pub order_id: u64,
pub authorized: bool,
}
unsafe impl Callback for MicroTxnAuthorizationResponse {
const ID: i32 = 152;
const SIZE: i32 = std::mem::size_of::<sys::MicroTxnAuthorizationResponse_t>() as i32;
unsafe fn from_raw(raw: *mut c_void) -> Self {
let val = &mut *(raw as *mut sys::MicroTxnAuthorizationResponse_t);
MicroTxnAuthorizationResponse {
app_id: val.m_unAppID.into(),
order_id: val.m_ulOrderID.into(),
authorized: val.m_bAuthorized == 1,
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SteamServersConnected;
unsafe impl Callback for SteamServersConnected {
const ID: i32 = 101;
const SIZE: i32 = ::std::mem::size_of::<sys::SteamServersConnected_t>() as i32;
unsafe fn from_raw(_: *mut c_void) -> Self {
SteamServersConnected
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SteamServersDisconnected {
pub reason: SteamError,
}
unsafe impl Callback for SteamServersDisconnected {
const ID: i32 = 103;
const SIZE: i32 = ::std::mem::size_of::<sys::SteamServersDisconnected_t>() as i32;
unsafe fn from_raw(raw: *mut c_void) -> Self {
let val = &mut *(raw as *mut sys::SteamServersDisconnected_t);
SteamServersDisconnected {
reason: val.m_eResult.into(),
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SteamServerConnectFailure {
pub reason: SteamError,
pub still_retrying: bool,
}
unsafe impl Callback for SteamServerConnectFailure {
const ID: i32 = 102;
const SIZE: i32 = ::std::mem::size_of::<sys::SteamServerConnectFailure_t>() as i32;
unsafe fn from_raw(raw: *mut c_void) -> Self {
let val = &mut *(raw as *mut sys::SteamServerConnectFailure_t);
SteamServerConnectFailure {
reason: val.m_eResult.into(),
still_retrying: val.m_bStillRetrying,
}
}
}
#[derive(Clone, Debug, Error)]
pub enum AuthSessionValidateError {
#[error("user not connected to steam")]
UserNotConnectedToSteam,
#[error("the license has expired")]
NoLicenseOrExpired,
#[error("the user is VAC banned from this game")]
VACBanned,
#[error("the user is logged in elsewhere")]
LoggedInElseWhere,
#[error("VAC check timed out")]
VACCheckTimedOut,
#[error("the authentication ticket has been cancelled")]
AuthTicketCancelled,
#[error("the authentication ticket has already been used")]
AuthTicketInvalidAlreadyUsed,
#[error("the authentication ticket is invalid")]
AuthTicketInvalid,
#[error("the user is banned")]
PublisherIssuedBan,
}