From df68c990fc3633cc9cf2d376d906d0c28ed9f7b8 Mon Sep 17 00:00:00 2001 From: Dessa Simpson Date: Sun, 5 Jul 2020 11:46:41 -0700 Subject: [PATCH] Implement Twitch API connector --- package-lock.json | 19 +++++++++++++++++++ package.json | 1 + public/index.html | 2 +- src/app.ts | 28 +++++++++++++++++++++++++++- src/config.ts | 12 ++++++++++++ src/twitch.ts | 25 +++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 src/twitch.ts diff --git a/package-lock.json b/package-lock.json index 0717d33..f798792 100644 --- a/package-lock.json +++ b/package-lock.json @@ -493,6 +493,11 @@ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", "dev": true }, + "data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -658,6 +663,11 @@ } } }, + "fetch-blob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-2.0.1.tgz", + "integrity": "sha512-1jFpa68M4EzObtFa7XOKZoN1unsaeJ6hGSbxaWaVO+TkHmVvnyzRu1ktZAFbUvTZ9NC/qMKGKJ79dK4MzuSBiw==" + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1024,6 +1034,15 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "node-fetch": { + "version": "3.0.0-beta.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.0.0-beta.7.tgz", + "integrity": "sha512-UTmmxR2RCLiGL0q61p8DgMgw1UXd10+XVB77IHG55flJ/tHqQQXloNTm5dd/mB3RNXP3+CJPf++t0nb3whKNkw==", + "requires": { + "data-uri-to-buffer": "^3.0.1", + "fetch-blob": "^2.0.0" + } + }, "nodemon": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", diff --git a/package.json b/package.json index 13d7cfd..b91dfb1 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "connect-pg-simple": "^6.1.0", "express": "^4.17.1", "express-session": "^1.17.1", + "node-fetch": "^3.0.0-beta.7", "pg": "^8.2.1" }, "devDependencies": { diff --git a/public/index.html b/public/index.html index fa60c05..5a4a3af 100644 --- a/public/index.html +++ b/public/index.html @@ -9,7 +9,7 @@
- +

diff --git a/src/app.ts b/src/app.ts index f70fb4a..14d8719 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,9 +1,12 @@ import * as config from "./config"; import * as requests from "./requests"; +import * as twitch from "./twitch"; +import { URLSearchParams } from "url"; import { QueryResult } from "pg"; import express from "express"; import session from "express-session"; import pgSessionStore from "connect-pg-simple"; +import fetch, { Response as FetchResponse } from "node-fetch"; import db from "./db"; import errorHandler from "./errors"; @@ -14,9 +17,12 @@ app.use(session({ secret: config.sessionSecret, saveUninitialized: false, resave: false, - store: new (pgSessionStore(session))() + store: new (pgSessionStore(session))({ + pool: db + }) })); +// API app.get("/api/getRequests", async (request, response) => { var requestCount = ( request.query.count ? parseInt(request.query.count as string, 10) : 5 ); requests.getRequests(requestCount).then((val: QueryResult) => response.send(val)) @@ -101,6 +107,26 @@ app.post("/api/deleteRequest", async (request, response) => { .catch((e: any) => errorHandler(request,response,e)); }); +// Twitch callback +app.get("/callback", async (request, response) => { + var authcode = request.query.code as string; + var tokenResponse = await fetch("https://id.twitch.tv/oauth2/token", { method: "POST", body: new URLSearchParams({ + client_id: config.twitchClientId, + client_secret: config.twitchSecret, + code: authcode, + grant_type: "authorization_code", + redirect_uri: `${config.urlPrefix}/callback` + })}).then((res: FetchResponse) => res.json() as Promise) + .catch((e: any) => errorHandler(request,response,e)); + if (typeof request.session == 'undefined') throw new Error('Session is undefined'); + if (typeof tokenResponse == 'undefined') throw new Error('tokenResponse is undefined'); + request.session.tokenpair = { access_token: tokenResponse.access_token, refresh_token: tokenResponse.refresh_token }; + request.session.user = (await twitch.apiRequest(request.session.tokenpair,"GET","/users")).data[0]; + response.redirect(307, '/'); +}); + +//app.get("/session", (request, response) => { response.send(request.session); }); + const server = app.listen(config.port, () => { console.log(`Listening on port ${config.port}`); }); diff --git a/src/config.ts b/src/config.ts index 62799d0..378e078 100644 --- a/src/config.ts +++ b/src/config.ts @@ -4,6 +4,18 @@ if (!process.env.PORT) { } export const port: number = parseInt(process.env.PORT as string, 10); +if (!process.env.URL_PREFIX) { + console.log("Missing environment variable URL_PREFIX"); + process.exit(1); +} +export const urlPrefix: string = process.env.URL_PREFIX; + +if (!process.env.TWITCH_CLIENTID) { + console.log("Missing environment variable TWITCH_CLIENTID"); + process.exit(1); +} +export const twitchClientId: string = process.env.TWITCH_CLIENTID; + if (!process.env.TWITCH_SECRET) { console.log("Missing environment variable TWITCH_SECRET"); process.exit(1); diff --git a/src/twitch.ts b/src/twitch.ts new file mode 100644 index 0000000..850c399 --- /dev/null +++ b/src/twitch.ts @@ -0,0 +1,25 @@ +import * as config from "./config"; +import fetch, { Response as FetchResponse } from "node-fetch"; + +export interface TokenResponse { + access_token: string; + refresh_token: string; + token_type: string; + expires_in: number; +} + +export interface TokenPair { + access_token: string; + refresh_token: string; +} + +export async function apiRequest(tokens: TokenPair, method: string, endpoint: string): Promise; +export async function apiRequest(tokens: TokenPair, method: string, endpoint: string, query: string): Promise; +export async function apiRequest(tokens: TokenPair, method: string, endpoint: string, query?: string,) { + var headers = { + "Authorization": "Bearer " + tokens.access_token, + "Client-ID": config.twitchClientId + }; + return fetch("https://api.twitch.tv/helix" + endpoint, { method: method, headers: headers}) + .then(async (res: FetchResponse) => res.json()); +}