Move auth storage to database

This commit is contained in:
2025-03-29 19:05:02 +01:00
7 changed files with 53 additions and 13 deletions

3
.example.env Normal file
View File

@@ -0,0 +1,3 @@
CLIENT_ID=
CLIENT_SECRET=
OAUTH_CODE=

View File

@@ -17,7 +17,6 @@ COPY . .
FROM base AS release FROM base AS release
COPY --from=install /temp/prod/node_modules node_modules COPY --from=install /temp/prod/node_modules node_modules
COPY --from=prerelease /app/src ./src COPY --from=prerelease /app/src ./src
COPY --from=prerelease /app/auth.json .
COPY --from=prerelease /app/package.json . COPY --from=prerelease /app/package.json .
CMD [ "bun", "." ] CMD [ "bun", "." ]

View File

@@ -1,8 +0,0 @@
{
"CLIENT_ID": "",
"CLIENT_SECRET": "",
"ACCESS_TOKEN": "",
"REFRESH_TOKEN": "",
"EXPIRESIN": 0,
"OBTAINMENTTIMESTAMP": 0
}

View File

@@ -6,6 +6,7 @@
"@twurple/api": "^7.2.1", "@twurple/api": "^7.2.1",
"@twurple/chat": "^7.2.1", "@twurple/chat": "^7.2.1",
"@twurple/easy-bot": "^7.2.1", "@twurple/easy-bot": "^7.2.1",
"pocketbase": "^0.25.2",
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.2.8", "@types/bun": "^1.2.8",
@@ -63,6 +64,8 @@
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
"pocketbase": ["pocketbase@0.25.2", "", {}, "sha512-ONZl1+qHJMnhR2uacBlBJ90lm7njtL/zy0606+1ROfK9hSL4LRBRc8r89rMcNRzPzRqCNyoFTh2Qg/lYXdEC1w=="],
"retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="],
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],

View File

@@ -19,3 +19,7 @@ services:
watch: watch:
- action: rebuild - action: rebuild
path: ./src path: ./src
environment:
- CLIENT_ID=$CLIENT_ID
- CLIENT_SECRET=$CLIENT_SECRET
- OAUTH_CODE=$OAUTH_CODE

View File

@@ -3,7 +3,8 @@
"dependencies": { "dependencies": {
"@twurple/api": "^7.2.1", "@twurple/api": "^7.2.1",
"@twurple/chat": "^7.2.1", "@twurple/chat": "^7.2.1",
"@twurple/easy-bot": "^7.2.1" "@twurple/easy-bot": "^7.2.1",
"pocketbase": "^0.25.2"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.2.8" "@types/bun": "^1.2.8"

View File

@@ -1,6 +1,41 @@
import { RefreshingAuthProvider } from '@twurple/auth' import { RefreshingAuthProvider, exchangeCode } from '@twurple/auth'
import PocketBase from 'pocketbase'
let auth = await Bun.file('auth.json').json() const pb = new PocketBase('http://pocketbase:8090')
const ttvauth = await pb.collection('ttvauth').getFullList()
let auth = ttvauth.length === 0 ? await firstAccess() : ttvauth[0].auth
async function firstAccess() {
// This function gets the required auth codes, and stores it in pocketbase
// The environment variables can be dropped after first run
const CLIENT_ID = process.env.CLIENT_ID
const CLIENT_SECRET = process.env.CLIENT_SECRET
const OAUTH_CODE = process.env.OAUTH_CODE
if (!CLIENT_ID) {console.error("No 'CLIENT_ID' for OAuth defined in environment variables."); process.exit(1)}
if (!CLIENT_SECRET) {console.error("No 'CLIENT_SECRET' for OAuth defined in environment variables."); process.exit(1)}
if (!OAUTH_CODE) {console.error("No 'OAUTH_CODE' provided. To get the code, please visit this URL, authorize the bot and copy the 'code' from the return URL.")
console.error(`https://id.twitch.tv/oauth2/authorize?client_id=${CLIENT_ID}&redirect_uri=http://localhost&response_type=code&scope=chat:read+chat:edit+moderator:manage:banned_users`)
process.exit(1)
}
const tokens = await exchangeCode(CLIENT_ID, CLIENT_SECRET, OAUTH_CODE, "http://localhost")
const auth = {
CLIENT_ID,
CLIENT_SECRET,
ACCESS_TOKEN: tokens.accessToken,
REFRESH_TOKEN: tokens.refreshToken,
EXPIRESIN: tokens.expiresIn,
OBTAINMENTTIMESTAMP: tokens.obtainmentTimestamp
}
await pb.collection('ttvauth').create({auth})
return auth
}
// At this point, it is required that the auth variable is properly loaded from the database
const authProvider = new RefreshingAuthProvider({ const authProvider = new RefreshingAuthProvider({
clientId: auth.CLIENT_ID, clientId: auth.CLIENT_ID,
@@ -19,7 +54,10 @@ authProvider.onRefresh(async (_id, newTokenData) => {
auth.REFRESH_TOKEN = newTokenData.refreshToken! auth.REFRESH_TOKEN = newTokenData.refreshToken!
auth.EXPIRESIN = newTokenData.expiresIn! auth.EXPIRESIN = newTokenData.expiresIn!
auth.OBTAINMENTTIMESTAMP = newTokenData.obtainmentTimestamp auth.OBTAINMENTTIMESTAMP = newTokenData.obtainmentTimestamp
await Bun.file('auth.json').write(JSON.stringify(auth))
const ttvauthid = await pb.collection('ttvauth').getFullList()
await pb.collection('ttvauth').update(ttvauthid[0].id, {auth})
console.log("Refreshed OAuth tokens.") console.log("Refreshed OAuth tokens.")
}) })