diff --git a/.example.env b/.example.env new file mode 100644 index 0000000..22f6e7f --- /dev/null +++ b/.example.env @@ -0,0 +1,3 @@ +CLIENT_ID= +CLIENT_SECRET= +OAUTH_CODE= diff --git a/.gitea/workflows/docker.yml b/.gitea/workflows/docker.yml index 8d7edbf..ae04e8e 100644 --- a/.gitea/workflows/docker.yml +++ b/.gitea/workflows/docker.yml @@ -23,4 +23,4 @@ jobs: file: Dockerfile.dogbot context: . push: true - tags: git.qwerinope.com/dogbot:latest + tags: git.qwerinope.com/qwerinope/dogbot:latest diff --git a/Dockerfile.dogbot b/Dockerfile.dogbot index 3290cc2..cb377c0 100644 --- a/Dockerfile.dogbot +++ b/Dockerfile.dogbot @@ -17,7 +17,6 @@ COPY . . FROM base AS release COPY --from=install /temp/prod/node_modules node_modules COPY --from=prerelease /app/src ./src -COPY --from=prerelease /app/auth.json . COPY --from=prerelease /app/package.json . CMD [ "bun", "." ] \ No newline at end of file diff --git a/auth.example.json b/auth.example.json deleted file mode 100644 index 3979d8a..0000000 --- a/auth.example.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "CLIENT_ID": "", - "CLIENT_SECRET": "", - "ACCESS_TOKEN": "", - "REFRESH_TOKEN": "", - "EXPIRESIN": 0, - "OBTAINMENTTIMESTAMP": 0 -} diff --git a/bun.lock b/bun.lock index 40f57ba..8d424ee 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "@twurple/api": "^7.2.1", "@twurple/chat": "^7.2.1", "@twurple/easy-bot": "^7.2.1", + "pocketbase": "^0.25.2", }, "devDependencies": { "@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=="], + "pocketbase": ["pocketbase@0.25.2", "", {}, "sha512-ONZl1+qHJMnhR2uacBlBJ90lm7njtL/zy0606+1ROfK9hSL4LRBRc8r89rMcNRzPzRqCNyoFTh2Qg/lYXdEC1w=="], + "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], diff --git a/compose.yml b/compose.yml index 6628cd3..660009c 100644 --- a/compose.yml +++ b/compose.yml @@ -19,3 +19,7 @@ services: watch: - action: rebuild path: ./src + environment: + - CLIENT_ID=$CLIENT_ID + - CLIENT_SECRET=$CLIENT_SECRET + - OAUTH_CODE=$OAUTH_CODE diff --git a/package.json b/package.json index 429a365..843454f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "dependencies": { "@twurple/api": "^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": { "@types/bun": "^1.2.8" diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 9bd62f7..d77fae4 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -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({ clientId: auth.CLIENT_ID, @@ -19,7 +54,10 @@ authProvider.onRefresh(async (_id, newTokenData) => { auth.REFRESH_TOKEN = newTokenData.refreshToken! auth.EXPIRESIN = newTokenData.expiresIn! 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.") })