From 2e19ad2800dc822a98e9ccca6059738642808426 Mon Sep 17 00:00:00 2001 From: Govorunb Date: Wed, 12 Jun 2024 02:15:11 +1000 Subject: [PATCH] send user info (closes #18) remove ability to pick announce --- common/types.ts | 12 +-------- ebs/package.json | 1 + ebs/src/modules/game/connection.ts | 13 +++++----- ebs/src/modules/game/messages.ts | 6 ++--- ebs/src/modules/transactions.ts | 40 +++++++++++++++++++++--------- ebs/src/util/twitch.ts | 12 +++++++++ 6 files changed, 52 insertions(+), 32 deletions(-) create mode 100644 ebs/src/util/twitch.ts diff --git a/common/types.ts b/common/types.ts index 9faf6cc..ad7e5d6 100644 --- a/common/types.ts +++ b/common/types.ts @@ -6,15 +6,6 @@ export const enum LiteralTypes { Vector } -export const enum AnnounceType { - DefaultAnnounce, - DefaultSilent, - // e.g. "add signal" - AlwaysAnnounce, - // e.g. "say"/"hint" (because the message itself is the announcement) - AlwaysSilent, -} - type EnumTypeName = string; type ParamType = LiteralTypes | EnumTypeName; @@ -63,7 +54,7 @@ export type Redeem = { title: string; description: string; args: Parameter[]; - announce?: AnnounceType; + announce?: boolean; moderated?: boolean; image: string; @@ -86,7 +77,6 @@ export type Cart = { id: string; sku: string; args: { [name: string]: any }; - announce: boolean; }; export type IdentifiableCart = Cart & { diff --git a/ebs/package.json b/ebs/package.json index 360621a..a5392a6 100644 --- a/ebs/package.json +++ b/ebs/package.json @@ -7,6 +7,7 @@ "build": "esbuild --bundle --minify --platform=node --sourcemap=inline --outfile=dist/index.js src/index.ts" }, "dependencies": { + "@twurple/api": "^7.1.0", "@twurple/ebs-helper": "^7.1.0", "body-parser": "^1.20.2", "cors": "^2.8.5", diff --git a/ebs/src/modules/game/connection.ts b/ebs/src/modules/game/connection.ts index 0ebffa2..f83b3a3 100644 --- a/ebs/src/modules/game/connection.ts +++ b/ebs/src/modules/game/connection.ts @@ -1,9 +1,9 @@ -import { Message, MessageType } from "./messages"; -import { ResultMessage, HelloMessage, GameMessage } from "./messages.game"; +import { Message, MessageType, TwitchUser } from "./messages"; +import { ResultMessage, GameMessage } from "./messages.game"; import * as ServerWS from "ws"; import { v4 as uuid } from "uuid"; import { CommandInvocationSource, RedeemMessage, ServerMessage } from "./messages.server"; -import { Redeem } from "common/types"; +import { Cart, Redeem } from "common/types"; const VERSION = "0.1.0"; @@ -124,7 +124,7 @@ export class GameConnection { timestamp: Date.now() } } - public redeem(redeem: Redeem, args: {[name: string]: any}, announce: boolean, transactionId: string) { + public redeem(redeem: Redeem, cart: Cart, user: TwitchUser, transactionId: string) { if (!transactionId) { console.error(`Tried to redeem without transaction ID`); return; @@ -136,8 +136,9 @@ export class GameConnection { source: CommandInvocationSource.Swarm, command: redeem.id, title: redeem.title, - announce, - args + announce: redeem.announce, + args: cart.args, + user } as RedeemMessage; if (this.outstandingRedeems.has(msg.guid)) { console.error(`Redeeming ${msg.guid} more than once`); diff --git a/ebs/src/modules/game/messages.ts b/ebs/src/modules/game/messages.ts index ab35967..70b9810 100644 --- a/ebs/src/modules/game/messages.ts +++ b/ebs/src/modules/game/messages.ts @@ -24,10 +24,10 @@ export type Message = { } export type TwitchUser = { - /** Channel id */ - id: number, + /** Numeric user id */ + id: string, /** Twitch username (login name) */ - userName: string, + login: string, /** User's chosen display name. */ displayName: string } \ No newline at end of file diff --git a/ebs/src/modules/transactions.ts b/ebs/src/modules/transactions.ts index 165426b..faecdad 100644 --- a/ebs/src/modules/transactions.ts +++ b/ebs/src/modules/transactions.ts @@ -7,6 +7,8 @@ import { getConfig } from "./config"; import { getPrepurchase, isReceiptUsed, isUserBanned, registerPrepurchase, deletePrepurchase } from "../util/db"; import { logToDiscord } from "../util/logger"; import { connection } from "./game"; +import { TwitchUser } from "./game/messages"; +import { getHelixUser } from "../util/twitch"; app.post("/public/prepurchase", async (req, res) => { const cart = req.body as Cart; @@ -213,30 +215,32 @@ app.post("/public/transaction", async (req, res) => { ], }).then(); } else { - const redeemAnnounce = redeem.announce || 0; - const [doAnnounce, canChange] = [!(redeemAnnounce & 1), !(redeemAnnounce & 2)]; // funny - // don't allow to change when you shouldn't - if (cart.announce != doAnnounce && !canChange) { + let userInfo = await getTwitchUser(cart.userId); + if (!userInfo) { logToDiscord({ transactionToken: transaction.token, userIdInsecure: req.twitchAuthorization!.user_id!, important: false, fields: [ { - header: "Invalid announce", + header: "Could not get Twitch user info", content: { config: currentConfig.version, cart: cart, transaction: transaction, - announceType: redeemAnnounce, - userPicked: cart.announce, - }, - }, - ], + error: userInfo, + } + } + ] }); - cart.announce = doAnnounce!; + // very much not ideal but they've already paid... so... + userInfo = { + id: cart.userId, + login: cart.userId, + displayName: cart.userId, + } } - connection.redeem(redeem, cart.args, cart.announce, transaction.token); + connection.redeem(redeem, cart, userInfo, transaction.token); } res.sendStatus(200); @@ -268,3 +272,15 @@ app.post("/public/transaction/cancel", async (req, res) => { res.sendStatus(404); } }); + +async function getTwitchUser(id: string): Promise { + const user = await getHelixUser(id); + if (!user) { + return null; + } + return { + id: user.id, + displayName: user.displayName, + login: user.name, + } +} \ No newline at end of file diff --git a/ebs/src/util/twitch.ts b/ebs/src/util/twitch.ts new file mode 100644 index 0000000..b7a9019 --- /dev/null +++ b/ebs/src/util/twitch.ts @@ -0,0 +1,12 @@ +import { ApiClient, HelixUser } from "@twurple/api"; +import { RefreshingAuthProvider } from "@twurple/auth"; + +const authProvider = new RefreshingAuthProvider({ + clientId: process.env.TWITCH_API_CLIENT_ID!, + clientSecret: process.env.TWITCH_API_CLIENT_SECRET! +}); +const api = new ApiClient({authProvider, batchDelay: 100}); + +export async function getHelixUser(userId: string): Promise { + return api.users.getUserByIdBatched(userId); +}