mirror of
https://github.com/icewind1991/mx-puppet-steam.git
synced 2026-06-03 17:44:09 +02:00
seems to work somewhat
This commit is contained in:
commit
7efed83afd
12 changed files with 7432 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
node_modules
|
||||||
|
build
|
||||||
|
.env
|
||||||
|
config.yaml
|
||||||
|
*-registration.yaml
|
||||||
|
database.db
|
||||||
3280
package-lock.json
generated
Normal file
3280
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
29
package.json
Normal file
29
package.json
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "mx-puppet-nextcloud",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "Puppeting bridge for nextcloud talk",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"lint": "tslint --project ./tsconfig.json -t stylish",
|
||||||
|
"start": "npm run-script build && node ./build/index.js",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "Icewind",
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "^1.19.0",
|
||||||
|
"command-line-args": "^5.1.1",
|
||||||
|
"command-line-usage": "^5.0.5",
|
||||||
|
"js-yaml": "^3.13.1",
|
||||||
|
"mx-puppet-bridge": "0.0.40",
|
||||||
|
"steam-user": "4.15.1",
|
||||||
|
"steamcommunity": "3.41.3",
|
||||||
|
"steamid": "1.1.3",
|
||||||
|
"tslint": "^5.20.1",
|
||||||
|
"typescript": "^3.8.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^12.12.37",
|
||||||
|
"@types/steamid": "^1.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
3423
src/@types/steam-user/enum.d.ts
vendored
Normal file
3423
src/@types/steam-user/enum.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
22
src/@types/steam-user/index.d.ts
vendored
Normal file
22
src/@types/steam-user/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
// declare module 'steam-user' {
|
||||||
|
// export * from "steam-user-enums";
|
||||||
|
//
|
||||||
|
// export interface ILoginParams {
|
||||||
|
// accountName: string;
|
||||||
|
// password: string;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// export class Chat {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// export default class SteamUser {
|
||||||
|
// constructor();
|
||||||
|
//
|
||||||
|
// public logOn(params: any): void;
|
||||||
|
//
|
||||||
|
// public on(hook: string, callback: any): void;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
54
src/@types/steam-user/interfaces.d.ts
vendored
Normal file
54
src/@types/steam-user/interfaces.d.ts
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
declare module 'steam-user-interfaces' {
|
||||||
|
import {EChatEntryType, EChatRoomServerMessage} from "steam-user-enums";
|
||||||
|
import SteamId from "steamid";
|
||||||
|
|
||||||
|
export interface IIncomingFriendMessage {
|
||||||
|
steamid_friend: SteamId,
|
||||||
|
chat_entry_type: EChatEntryType,
|
||||||
|
from_limited_account: boolean,
|
||||||
|
message: string,
|
||||||
|
message_no_bbcode: string,
|
||||||
|
server_timestamp: Date,
|
||||||
|
ordinal: number,
|
||||||
|
local_echo: boolean,
|
||||||
|
low_priority: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IIncomingChatMessage {
|
||||||
|
chat_group_id: string,
|
||||||
|
chat_id: string,
|
||||||
|
steamid_sender: SteamId,
|
||||||
|
chat_entry_type: EChatEntryType,
|
||||||
|
from_limited_account: boolean,
|
||||||
|
message: string,
|
||||||
|
message_no_bbcode: string,
|
||||||
|
server_timestamp: Date,
|
||||||
|
ordinal: number,
|
||||||
|
mentions: IChatMentions | null,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IChatMentions {
|
||||||
|
mention_all: boolean,
|
||||||
|
mention_here,
|
||||||
|
mention_steamids: SteamId[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IServerMessage {
|
||||||
|
message: EChatRoomServerMessage,
|
||||||
|
string_param?: string,
|
||||||
|
steamid_param?: SteamId
|
||||||
|
}
|
||||||
|
|
||||||
|
// incomplete
|
||||||
|
export interface IPersona {
|
||||||
|
player_name: string,
|
||||||
|
avatar_hash: Buffer,
|
||||||
|
last_logoff: Date,
|
||||||
|
last_logon: Date,
|
||||||
|
last_seen_online: Date,
|
||||||
|
game_name: string,
|
||||||
|
avatar_url_icon: string,
|
||||||
|
avatar_url_medium: string,
|
||||||
|
avatar_url_full: string
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/config.ts
Normal file
16
src/config.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
export class NextcloudConfigWrap {
|
||||||
|
public nextcloud: NextcloudConfig = new NextcloudConfig();
|
||||||
|
|
||||||
|
public applyConfig(newConfig: { [key: string]: any }, configLayer: { [key: string]: any } = this) {
|
||||||
|
Object.keys(newConfig).forEach((key) => {
|
||||||
|
if (configLayer[key] instanceof Object && !(configLayer[key] instanceof Array)) {
|
||||||
|
this.applyConfig(newConfig[key], configLayer[key]);
|
||||||
|
} else {
|
||||||
|
configLayer[key] = newConfig[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NextcloudConfig {
|
||||||
|
}
|
||||||
170
src/index.ts
Normal file
170
src/index.ts
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
import {
|
||||||
|
PuppetBridge,
|
||||||
|
IProtocolInformation,
|
||||||
|
IPuppetBridgeRegOpts,
|
||||||
|
Log,
|
||||||
|
IRetData,
|
||||||
|
} from "mx-puppet-bridge";
|
||||||
|
import * as commandLineArgs from "command-line-args";
|
||||||
|
import * as commandLineUsage from "command-line-usage";
|
||||||
|
import * as escapeHtml from "escape-html";
|
||||||
|
import {Steam} from "./steam";
|
||||||
|
import {NextcloudConfigWrap} from "./config";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import * as yaml from "js-yaml";
|
||||||
|
import {GetDataFromStrHook, IPuppetData} from "mx-puppet-bridge/lib/src";
|
||||||
|
import * as SteamCommunity from 'steamcommunity';
|
||||||
|
import {LoginDetails, LoginToken} from "./login";
|
||||||
|
import * as SteamID from "steamid";
|
||||||
|
import * as SteamUser from "steam-user";
|
||||||
|
|
||||||
|
const log = new Log("NextcloudPuppet:index");
|
||||||
|
|
||||||
|
const commandOptions = [
|
||||||
|
{name: "register", alias: "r", type: Boolean},
|
||||||
|
{name: "registration-file", alias: "f", type: String},
|
||||||
|
{name: "config", alias: "c", type: String},
|
||||||
|
{name: "help", alias: "h", type: Boolean},
|
||||||
|
];
|
||||||
|
const options = Object.assign({
|
||||||
|
"register": false,
|
||||||
|
"registration-file": "steam-registration.yaml",
|
||||||
|
"config": "config.yaml",
|
||||||
|
"help": false,
|
||||||
|
}, commandLineArgs(commandOptions));
|
||||||
|
|
||||||
|
if (options.help) {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
|
console.log(commandLineUsage([
|
||||||
|
{
|
||||||
|
header: "Matrix Stream Puppet Bridge",
|
||||||
|
content: "A matrix puppet bridge for steam",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Options",
|
||||||
|
optionList: commandOptions,
|
||||||
|
},
|
||||||
|
]));
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const protocol = {
|
||||||
|
features: {typingTimeout : 1 * 1000},
|
||||||
|
id: "steam",
|
||||||
|
displayname: "Steam",
|
||||||
|
externalUrl: "https://steamcommunity.com/",
|
||||||
|
} as IProtocolInformation;
|
||||||
|
|
||||||
|
const puppet = new PuppetBridge(options["registration-file"], options.config, protocol);
|
||||||
|
|
||||||
|
if (options.register) {
|
||||||
|
// okay, all we have to do is generate a registration file
|
||||||
|
puppet.readConfig(false);
|
||||||
|
try {
|
||||||
|
puppet.generateRegistration({
|
||||||
|
prefix: "_steampuppet_",
|
||||||
|
id: "steam-puppet",
|
||||||
|
url: `http://${puppet.Config.bridge.bindAddress}:${puppet.Config.bridge.port}`,
|
||||||
|
} as IPuppetBridgeRegOpts);
|
||||||
|
} catch (err) {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
|
console.log("Couldn't generate registration file:", err);
|
||||||
|
}
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let config: NextcloudConfigWrap = new NextcloudConfigWrap();
|
||||||
|
|
||||||
|
function readConfig() {
|
||||||
|
config = new NextcloudConfigWrap();
|
||||||
|
config.applyConfig(yaml.safeLoad(fs.readFileSync(options.config)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Config(): NextcloudConfigWrap {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
await puppet.init();
|
||||||
|
// readConfig();
|
||||||
|
const steam = new Steam(puppet);
|
||||||
|
puppet.on("puppetNew", steam.newPuppet.bind(steam));
|
||||||
|
puppet.on("puppetDelete", steam.deletePuppet.bind(steam));
|
||||||
|
puppet.on("message", steam.handleMatrixMessage.bind(steam));
|
||||||
|
puppet.on("image", steam.handleMatrixImage.bind(steam));
|
||||||
|
puppet.on("video", steam.handleMatrixVideo.bind(steam));
|
||||||
|
puppet.setCreateUserHook(steam.createUser.bind(steam));
|
||||||
|
// puppet.setGetUserIdsInRoomHook(steam.getUserIdsInRoom.bind(steam));
|
||||||
|
puppet.setGetDescHook(async (puppetId: number, data: any): Promise<string> => {
|
||||||
|
let s = "Steam";
|
||||||
|
if (data.screenName) {
|
||||||
|
s += ` as ${data.screenName}`;
|
||||||
|
}
|
||||||
|
if (data.name) {
|
||||||
|
s += ` (${data.name})`;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
});
|
||||||
|
puppet.setGetDataFromStrHook(async (str: string): Promise<IRetData> => {
|
||||||
|
if (!str) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: `Usage: link <username> <password>`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let [username, password] = str.split(" ", 2);
|
||||||
|
|
||||||
|
const client = new SteamUser();
|
||||||
|
|
||||||
|
let details: LoginDetails = {
|
||||||
|
accountName: username,
|
||||||
|
password,
|
||||||
|
rememberPassword: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
let successResolve = resolve;
|
||||||
|
|
||||||
|
client.on("loginKey", function(loginKey) {
|
||||||
|
|
||||||
|
successResolve({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
accountName: username,
|
||||||
|
loginKey
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
client.on("steamGuard", function(domain, cb) {
|
||||||
|
resolve({
|
||||||
|
success: false,
|
||||||
|
error: `Please provide steam guard code`,
|
||||||
|
fn: async (code) => {
|
||||||
|
cb(code);
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
successResolve = resolve;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("error", (err) => {
|
||||||
|
resolve({
|
||||||
|
success: false,
|
||||||
|
error: err.message
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.logOn(details);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
await puppet.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-floating-promises
|
||||||
|
run(); // start the thing!
|
||||||
71
src/login.ts
Normal file
71
src/login.ts
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
import SteamID from "steamid";
|
||||||
|
const SteamCommunity = require('steamcommunity');
|
||||||
|
|
||||||
|
function tryLogin(community, details): Promise<void> {
|
||||||
|
return new Promise((res, rej) => community.login(details, function(err) {
|
||||||
|
if (err) {
|
||||||
|
rej(err);
|
||||||
|
} else {
|
||||||
|
res();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginDetails {
|
||||||
|
"accountName": string,
|
||||||
|
"password": string,
|
||||||
|
"steamguard"?: string,
|
||||||
|
"authCode"?: string,
|
||||||
|
"twoFactorCode"?: string,
|
||||||
|
"captcha"?: string,
|
||||||
|
disableMobile?: boolean,
|
||||||
|
rememberPassword?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginToken {
|
||||||
|
accountName: string,
|
||||||
|
webLogonToken: string,
|
||||||
|
steamID: SteamID
|
||||||
|
}
|
||||||
|
|
||||||
|
// export async function login(details: LoginDetails, steamGuard?: () => Promise<string>, twoFactor?: () => Promise<string>, captcha?: (url: string) => Promise<string>): Promise<LoginToken> {
|
||||||
|
// let community = new SteamCommunity();
|
||||||
|
// while (true) {
|
||||||
|
// try {
|
||||||
|
// await tryLogin(details);
|
||||||
|
// return new Promise((res, rej) => community.getClientLogonToken((err, details) => {
|
||||||
|
// if (err) {
|
||||||
|
// rej(err);
|
||||||
|
// } else {
|
||||||
|
// res(details);
|
||||||
|
// }
|
||||||
|
// }));
|
||||||
|
// } catch (e) {
|
||||||
|
// switch (e.message) {
|
||||||
|
// case 'SteamGuard':
|
||||||
|
// if (steamGuard) {
|
||||||
|
// details.steamguard = await steamGuard();
|
||||||
|
// } else {
|
||||||
|
// throw new Error("No steamguard handler provided")
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case 'SteamGuardMobile':
|
||||||
|
// if (twoFactor) {
|
||||||
|
// details.twoFactorCode = await twoFactor();
|
||||||
|
// } else {
|
||||||
|
// throw new Error("No twoFactor handler provided")
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case 'CAPTCHA':
|
||||||
|
// if (captcha) {
|
||||||
|
// details.captcha = await captcha(e.captchaurl);
|
||||||
|
// } else {
|
||||||
|
// throw new Error("No twoFactor handler provided")
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// throw e
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
259
src/steam.ts
Normal file
259
src/steam.ts
Normal file
|
|
@ -0,0 +1,259 @@
|
||||||
|
/// <reference path="@types/steam-user/enum.d.ts" />
|
||||||
|
/// <reference path="@types/steam-user/interfaces.d.ts" />
|
||||||
|
|
||||||
|
import {
|
||||||
|
PuppetBridge,
|
||||||
|
Log,
|
||||||
|
IReceiveParams,
|
||||||
|
IRemoteRoom,
|
||||||
|
IRemoteUser,
|
||||||
|
IMessageEvent,
|
||||||
|
IFileEvent,
|
||||||
|
Util,
|
||||||
|
IRetList,
|
||||||
|
} from "mx-puppet-bridge";
|
||||||
|
import * as SteamUser from "steam-user";
|
||||||
|
import * as SteamID from "steamid";
|
||||||
|
import {IIncomingFriendMessage, IPersona} from "steam-user-interfaces";
|
||||||
|
|
||||||
|
const log = new Log("MatrixPuppet:Steam");
|
||||||
|
|
||||||
|
interface ISteamPuppet {
|
||||||
|
client: SteamUser;
|
||||||
|
data: any;
|
||||||
|
sentEventIds: string[];
|
||||||
|
typingUsers: { [key: string]: any };
|
||||||
|
knownPersonas: Map<string, IPersona>,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISteamPuppets {
|
||||||
|
[puppetId: number]: ISteamPuppet;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IPuppetParams {
|
||||||
|
accountName: string,
|
||||||
|
loginKey: string,
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Steam {
|
||||||
|
private puppets: ISteamPuppets = {};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private bridge: PuppetBridge,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPersona(p: ISteamPuppet, steamid: SteamID): Promise<IPersona> {
|
||||||
|
let steamIdString = steamid.toString();
|
||||||
|
let persona = p.knownPersonas.get(steamIdString)
|
||||||
|
if (persona) {
|
||||||
|
return persona;
|
||||||
|
} else if (p.client.users[steamIdString]) {
|
||||||
|
return p.client.users[steamIdString];
|
||||||
|
} else {
|
||||||
|
let {personas} = await p.client.getPersonas([steamid]);
|
||||||
|
let persona = personas[steamIdString];
|
||||||
|
p.knownPersonas.set(steamIdString, persona);
|
||||||
|
return persona;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getSendParams(puppetId: number, msg: IIncomingFriendMessage, fromSteamId?: SteamID): Promise<IReceiveParams> {
|
||||||
|
const p = this.puppets[puppetId];
|
||||||
|
|
||||||
|
let persona = await this.getPersona(p, fromSteamId ? fromSteamId : msg.steamid_friend);
|
||||||
|
|
||||||
|
return {
|
||||||
|
room: {
|
||||||
|
puppetId,
|
||||||
|
roomId: msg.steamid_friend.toString(),
|
||||||
|
isDirect: true,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
puppetId,
|
||||||
|
userId: fromSteamId ? fromSteamId.toString() : msg.steamid_friend.toString(),
|
||||||
|
name: persona.player_name,
|
||||||
|
avatarUrl: persona.avatar_url_medium
|
||||||
|
},
|
||||||
|
eventId: `${msg.server_timestamp.toISOString()}::${msg.ordinal}`,
|
||||||
|
} as IReceiveParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async newPuppet(puppetId: number, data: IPuppetParams) {
|
||||||
|
log.info(`Adding new Puppet: puppetId=${puppetId}`);
|
||||||
|
if (this.puppets[puppetId]) {
|
||||||
|
await this.deletePuppet(puppetId);
|
||||||
|
}
|
||||||
|
const client = new SteamUser();
|
||||||
|
|
||||||
|
this.puppets[puppetId] = {
|
||||||
|
client,
|
||||||
|
data,
|
||||||
|
sentEventIds: [],
|
||||||
|
typingUsers: {},
|
||||||
|
knownPersonas: new Map(),
|
||||||
|
} as ISteamPuppet;
|
||||||
|
try {
|
||||||
|
client.logOn({
|
||||||
|
accountName: data.accountName,
|
||||||
|
loginKey: data.loginKey
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("user", (steamId, persona) => {
|
||||||
|
this.puppets[puppetId].knownPersonas.set(steamId.toString(), persona);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("loggedOn", async (details) => {
|
||||||
|
await this.bridge.setUserId(puppetId, client.steamID.toString());
|
||||||
|
|
||||||
|
await this.bridge.sendStatusMessage(puppetId, `connected as ${details.vanity_url}(${client.steamID.toString()})!`);
|
||||||
|
})
|
||||||
|
|
||||||
|
client.on("loginKey", (loginKey) => {
|
||||||
|
console.log("got new login key");
|
||||||
|
data.loginKey = loginKey;
|
||||||
|
this.bridge.setPuppetData(puppetId, data);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.chat.on("friendMessage", (message) => {
|
||||||
|
this.handleFriendMessage(puppetId, message);
|
||||||
|
});
|
||||||
|
client.chat.on("friendMessageEcho", (message) => {
|
||||||
|
this.handleFriendMessage(puppetId, message, client.steamID);
|
||||||
|
});
|
||||||
|
client.chat.on("friendTyping", (message: IIncomingFriendMessage) => {
|
||||||
|
this.handleFriendTyping(puppetId, message);
|
||||||
|
})
|
||||||
|
|
||||||
|
client.on("error", (err) => {
|
||||||
|
log.error(`Failed to start up puppet ${puppetId}`, err);
|
||||||
|
this.bridge.sendStatusMessage(puppetId, `**disconnected!**: failed to connect. ${err}`);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
log.error(`Failed to start up puppet ${puppetId}`, err);
|
||||||
|
await this.bridge.sendStatusMessage(puppetId, `**disconnected!**: failed to connect. ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deletePuppet(puppetId: number) {
|
||||||
|
log.info(`Got signal to quit Puppet: puppetId=${puppetId}`);
|
||||||
|
const p = this.puppets[puppetId];
|
||||||
|
if (!p) {
|
||||||
|
return; // nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
p.client.logOff();
|
||||||
|
|
||||||
|
delete this.bridge[puppetId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleFriendMessage(puppetId: number, message: IIncomingFriendMessage, fromSteamId?: SteamID) {
|
||||||
|
const p = this.puppets[puppetId];
|
||||||
|
log.verbose("Got message from steam to pass on");
|
||||||
|
const typingKey = message.steamid_friend.toString();
|
||||||
|
|
||||||
|
if (p.typingUsers[typingKey]) {
|
||||||
|
// user is typing, stop that
|
||||||
|
await this.bridge.setUserTyping(p.typingUsers[typingKey], false);
|
||||||
|
delete p.typingUsers[typingKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.bridge.sendMessage(await this.getSendParams(puppetId, message, fromSteamId), {
|
||||||
|
body: message.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleFriendTyping(puppetId: number, message: IIncomingFriendMessage) {
|
||||||
|
const p = this.puppets[puppetId];
|
||||||
|
const typingKey = message.steamid_friend.toString();
|
||||||
|
|
||||||
|
p.typingUsers[typingKey] = {
|
||||||
|
room: {
|
||||||
|
puppetId,
|
||||||
|
roomId: message.steamid_friend.toString(),
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
puppetId,
|
||||||
|
userId: message.steamid_friend.toString(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
await this.bridge.setUserTyping(p.typingUsers[typingKey], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async sendMessageToSteam(
|
||||||
|
p: ISteamPuppet,
|
||||||
|
room: IRemoteRoom,
|
||||||
|
eventId: string,
|
||||||
|
msg: string,
|
||||||
|
mediaId?: string,
|
||||||
|
) {
|
||||||
|
let id = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
let _roomSteamId = new SteamID(room.name as string);
|
||||||
|
if (_roomSteamId.isValid()) {
|
||||||
|
const sendMessage = await p.client.chat.sendFriendMessage(room.roomId, msg);
|
||||||
|
id = `${sendMessage.server_timestamp.toISOString()}::${sendMessage.ordinal}`;
|
||||||
|
} else {
|
||||||
|
await this.bridge.sendStatusMessage(room.puppetId, `Sending group messages is currently not supported`);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
await this.bridge.sendStatusMessage(room.puppetId, `Sending group messages is currently not supported`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.bridge.eventSync.insert(room, eventId, id);
|
||||||
|
p.sentEventIds.push(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMatrixMessage(room: IRemoteRoom, data: IMessageEvent, event: any) {
|
||||||
|
const p = this.puppets[room.puppetId];
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.verbose("Got message to send on");
|
||||||
|
// room.roomId, data.body
|
||||||
|
await this.sendMessageToSteam(p, room, data.eventId!, data.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMatrixImage(room: IRemoteRoom, data: IFileEvent, event: any) {
|
||||||
|
const p = this.puppets[room.puppetId];
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.verbose("Got image to send on");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMatrixVideo(room: IRemoteRoom, data: IFileEvent, event: any) {
|
||||||
|
const p = this.puppets[room.puppetId];
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.verbose("Got video to send on");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createUser(user: IRemoteUser): Promise<IRemoteUser | null> {
|
||||||
|
const p = this.puppets[user.puppetId];
|
||||||
|
if (!p) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
log.info(`Got request to create user ${user.userId}`);
|
||||||
|
return {
|
||||||
|
userId: user.userId,
|
||||||
|
puppetId: user.puppetId,
|
||||||
|
name: user.name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// public async getUserIdsInRoom(room: IRemoteRoom): Promise<Set<string> | null> {
|
||||||
|
// const p = this.puppets[room.puppetId];
|
||||||
|
// const client: TalkClient = p.client;
|
||||||
|
// const participants = await client.getChat(room.roomId).get_participants();
|
||||||
|
// for (const participant of participants) {
|
||||||
|
// p.knownUserNames[participant.userId] = participant.displayName;
|
||||||
|
// }
|
||||||
|
// return new Set(participants.map((participant) => participant.userId));
|
||||||
|
// }
|
||||||
|
}
|
||||||
84
steamtest.ts
Normal file
84
steamtest.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
import * as SteamUser from "steam-user";
|
||||||
|
import {log} from "util";
|
||||||
|
import SteamID = require("steamid");
|
||||||
|
const SteamCommunity = require('steamcommunity');
|
||||||
|
let community = new SteamCommunity();
|
||||||
|
|
||||||
|
let user = new SteamUser() as any;
|
||||||
|
|
||||||
|
function tryLogin(details): Promise<void> {
|
||||||
|
return new Promise((res, rej) => community.login(details, function(err) {
|
||||||
|
if (err) {
|
||||||
|
rej(err);
|
||||||
|
} else {
|
||||||
|
res();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LoginDetails {
|
||||||
|
"accountName"?: string,
|
||||||
|
"password"?: string,
|
||||||
|
"steamguard"?: string,
|
||||||
|
"authCode"?: string,
|
||||||
|
"twoFactorCode"?: string,
|
||||||
|
"captcha"?: string,
|
||||||
|
"disableMobile"?: boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LoginToken {
|
||||||
|
accountName: string,
|
||||||
|
webLoginToken: string,
|
||||||
|
steamID: SteamID
|
||||||
|
}
|
||||||
|
|
||||||
|
async function login(details: LoginDetails, steamGuard?: () => Promise<string>, twoFactor?: () => Promise<string>, captcha?: (url: string) => Promise<string>): Promise<LoginToken> {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
await tryLogin(details);
|
||||||
|
return new Promise((res, rej) => community.getClientLogonToken((err, details) => {
|
||||||
|
if (err) {
|
||||||
|
rej(err);
|
||||||
|
} else {
|
||||||
|
res(details);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} catch (e) {
|
||||||
|
switch (e.message) {
|
||||||
|
case 'SteamGuard':
|
||||||
|
if (steamGuard) {
|
||||||
|
details.steamguard = await steamGuard();
|
||||||
|
} else {
|
||||||
|
throw new Error("No steamguard handler provided")
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'SteamGuardMobile':
|
||||||
|
if (twoFactor) {
|
||||||
|
details.twoFactorCode = await twoFactor();
|
||||||
|
} else {
|
||||||
|
throw new Error("No twoFactor handler provided")
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'CAPTCHA':
|
||||||
|
if (captcha) {
|
||||||
|
details.captcha = await captcha(e.captchaurl);
|
||||||
|
} else {
|
||||||
|
throw new Error("No twoFactor handler provided")
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
let details = {
|
||||||
|
"accountName": "icewind1991",
|
||||||
|
"password": ""
|
||||||
|
};
|
||||||
|
console.log(await login(details, undefined, async () => "WM3MR"));
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
18
tsconfig.json
Normal file
18
tsconfig.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"target": "es2016",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"inlineSourceMap": true,
|
||||||
|
"outDir": "./build",
|
||||||
|
"types": ["node"],
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"typeRoots": [ "./node_modules/@types"]
|
||||||
|
},
|
||||||
|
"compileOnSave": true,
|
||||||
|
"include": [
|
||||||
|
"src/**/*",
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue