Skip to content

Commit

Permalink
Add ability to send a machine ID to Steam for SteamClient logins
Browse files Browse the repository at this point in the history
  • Loading branch information
DoctorMcKay committed Oct 26, 2023
1 parent 818196e commit 82ebd2b
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 9 deletions.
25 changes: 19 additions & 6 deletions src/AuthenticationClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,20 @@ import {clearTimeout} from 'timers';
import EAuthTokenPlatformType from './enums-steam/EAuthTokenPlatformType';
import EOSType from './enums-steam/EOSType';
import EResult from './enums-steam/EResult';
import ESessionPersistence from './enums-steam/ESessionPersistence';
import ETokenRenewalType from './enums-steam/ETokenRenewalType';

import {getProtoForMethod} from './protobufs';
import ITransport, {ApiResponse} from './transports/ITransport';

import {API_HEADERS, decodeJwt, eresultError, getSpoofedHostname, isJwtValidForAudience} from './helpers';
import {
API_HEADERS,
createMachineId,
decodeJwt,
eresultError,
getSpoofedHostname,
isJwtValidForAudience
} from './helpers';
import {
CAuthentication_AccessToken_GenerateForApp_Request,
CAuthentication_AccessToken_GenerateForApp_Response,
Expand Down Expand Up @@ -61,6 +69,7 @@ export default class AuthenticationClient extends EventEmitter {
_webClient: HttpClient;
_transportCloseTimeout: NodeJS.Timeout;
_webUserAgent: string;
_machineId?: Buffer|boolean;

constructor(options: AuthenticationClientConstructorOptions) {
super();
Expand All @@ -72,6 +81,8 @@ export default class AuthenticationClient extends EventEmitter {
if (this._platformType == EAuthTokenPlatformType.WebBrowser) {
this._webClient.userAgent = options.webUserAgent;
}

this._machineId = options.machineId;
}

async getRsaKey(accountName: string): Promise<CAuthentication_GetPasswordRSAPublicKey_Response> {
Expand Down Expand Up @@ -102,17 +113,19 @@ export default class AuthenticationClient extends EventEmitter {
account_name: details.accountName,
encrypted_password: details.encryptedPassword,
encryption_timestamp: details.keyTimestamp,
remember_login: details.persistence == ESessionPersistence.Persistent,
persistence: details.persistence,
website_id: websiteId,
device_details: deviceDetails
};

if (details.platformType == EAuthTokenPlatformType.SteamClient) {
// At least for SteamClient logins, we don't supply device_details.
// TODO: check if this is true for other platform types
data.device_friendly_name = deviceDetails.device_friendly_name;
data.platform_type = deviceDetails.platform_type;
delete data.device_details;
// For SteamClient logins, we also need a machine id
if (this._machineId && Buffer.isBuffer(this._machineId)) {
data.device_details.machine_id = this._machineId;
} else if (this._machineId === true) {
data.device_details.machine_id = createMachineId(details.accountName);
}
}

if (details.steamGuardMachineToken) {
Expand Down
3 changes: 2 additions & 1 deletion src/LoginSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ export default class LoginSession extends TypedEmitter<LoginSessionEvents> {
platformType: this._platformType,
transport,
webClient: this._webClient,
webUserAgent: options.userAgent || defaultUserAgent()
webUserAgent: options.userAgent || defaultUserAgent(),
machineId: options.machineId
});
this._handler.on('debug', (...args) => this.emit('debug-handler', ...args));
this.on('debug', debug);
Expand Down
42 changes: 42 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,45 @@ export function getSpoofedHostname() {
export function defaultUserAgent() {
return chrome();
}

export function createMachineId(accountName: string): Buffer {
return Buffer.concat([
byteToBuffer(0),
stringToBuffer('MessageObject'),

byteToBuffer(1),
stringToBuffer('BB3'),
stringToBuffer(sha1(`SteamUser Hash BB3 ${accountName}`)),

byteToBuffer(1),
stringToBuffer('FF2'),
stringToBuffer(sha1(`SteamUser Hash FF2 ${accountName}`)),

byteToBuffer(1),
stringToBuffer('3B3'),
stringToBuffer(sha1(`SteamUser Hash 3B3 ${accountName}`)),

byteToBuffer(8),
byteToBuffer(8)
]);

function sha1(input) {
let hash = createHash('sha1');
hash.update(input, 'utf8');
return hash.digest('hex');
}

function stringToBuffer(input) {
let b = Buffer.from(input, 'utf8');
return Buffer.concat([
b,
Buffer.from('00', 'hex')
]);
}

function byteToBuffer(input) {
let b = Buffer.alloc(1);
b[0] = input;
return b;
}
}
9 changes: 8 additions & 1 deletion src/interfaces-external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,14 @@ export interface ConstructorOptions {
* A string containing the user-agent you want to use when communicating with Steam.
* Only effective when using EAuthTokenPlatformType.WebBrowser.
*/
userAgent?: string
userAgent?: string,

/**
* Your Steam machine ID, used for SteamClient logins. Pass a Buffer containing your well-formed machine ID, pass
* `true` to have steam-session internally generate a machine ID using the same formula that steam-user uses by
* default, or pass `false`, `null`, or omit to not send a machine ID.
*/
machineId?: Buffer|boolean
}

export interface StartLoginSessionWithCredentialsDetails {
Expand Down
3 changes: 2 additions & 1 deletion src/interfaces-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export interface AuthenticationClientConstructorOptions {
platformType: EAuthTokenPlatformType,
transport: ITransport,
webClient: HttpClient,
webUserAgent: string
webUserAgent: string,
machineId?: Buffer|boolean
}

export interface StartAuthSessionRequest {
Expand Down

0 comments on commit 82ebd2b

Please sign in to comment.