From 3cbc16ca90b02ea4c6c8f267402de1b918f48ec4 Mon Sep 17 00:00:00 2001 From: EngineerShawn <147225693+EngineerShawn@users.noreply.github.com> Date: Sat, 18 Nov 2023 05:57:30 -0800 Subject: [PATCH] deleted secretData.js and updated server.js --- backend/db.js | 0 backend/package-lock.json | 233 +++++++++++++++++++++++++++++++++++++- backend/package.json | 3 +- backend/secretData.js | 13 --- backend/server.js | 169 ++++++++++++++++++++------- 5 files changed, 362 insertions(+), 56 deletions(-) create mode 100644 backend/db.js delete mode 100644 backend/secretData.js diff --git a/backend/db.js b/backend/db.js new file mode 100644 index 00000000..e69de29b diff --git a/backend/package-lock.json b/backend/package-lock.json index 1b56e213..5a745fc9 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -12,12 +12,36 @@ "axios": "^1.6.2", "express": "^4.18.2", "path": "^0.12.7", - "pg": "^8.11.3" + "pg": "^8.11.3", + "winston": "^3.11.0" }, "devDependencies": { "dotenv": "^16.3.1" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -35,6 +59,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -102,6 +131,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -208,6 +277,11 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -270,6 +344,11 @@ "node": ">= 0.10.0" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -287,6 +366,11 @@ "node": ">= 0.8" } }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/follow-redirects": { "version": "1.15.3", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", @@ -451,6 +535,48 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/logform": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -534,6 +660,14 @@ "node": ">= 0.8" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/packet-reader": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", @@ -740,6 +874,19 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -759,6 +906,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -838,6 +993,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -846,6 +1009,14 @@ "node": ">= 10.x" } }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -854,6 +1025,19 @@ "node": ">= 0.8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -862,6 +1046,14 @@ "node": ">=0.6" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -890,6 +1082,11 @@ "inherits": "2.0.3" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/util/node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -911,6 +1108,40 @@ "node": ">= 0.8" } }, + "node_modules/winston": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", + "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", + "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/backend/package.json b/backend/package.json index df000151..fc47ac85 100644 --- a/backend/package.json +++ b/backend/package.json @@ -13,7 +13,8 @@ "axios": "^1.6.2", "express": "^4.18.2", "path": "^0.12.7", - "pg": "^8.11.3" + "pg": "^8.11.3", + "winston": "^3.11.0" }, "devDependencies": { "dotenv": "^16.3.1" diff --git a/backend/secretData.js b/backend/secretData.js deleted file mode 100644 index d27c4e18..00000000 --- a/backend/secretData.js +++ /dev/null @@ -1,13 +0,0 @@ -const path = require('path'); -require('dotenv').config({ path: '../.env' }); - -const secretData = { - token : process.env.NOVA_BOT_TOKEN, - client_id : process.env.CLIENT_ID, - client_secret : process.env.CLIENT_SECRET, - endpoint : process.env.DISCORD_API_ENDPOINT, - redirect : process.env.REDIRECT_URI, - port : process.env.PORT -}; - -module.exports = secretData; diff --git a/backend/server.js b/backend/server.js index 6dabadb4..f12d49b8 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,70 +1,157 @@ -/** - * ========================================================= -* NovaAI - Discord Bot - v1.0.0 - ========================================================= - * -* Product Page: (https://novaai.engineerpatterson.com) -* Copyright 2023 engineerpatterson.com (https://www.engineerpatterson.com/) -* Licensed under MIT (https://github.com/EngineerShawn/NovaAICrossPlatform/tree/main/NovaAI-Discord/LICENSE.md) - -* Design and Coded by Shawn Pattesron (EngineerPatterson) - * - * - * - * Server for Discord OAuth2 Request and POST - * - */ - const express = require('express'); const axios = require('axios'); -const app = express(); -const secretData = require('./secretData.js'); +const { Pool } = require('pg'); +const winston = require('winston'); +require('dotenv').config({path: '../.env'}); +// Logging Setup +const logger = winston.createLogger({ + level: 'info', + format: winston.format.combine( + winston.format.timestamp(), + winston.format.json() + ), + transports: [ + new winston.transports.Console({ format: winston.format.simple() }), + new winston.transports.File({ filename: 'combined.log' }) // Logs to a file + ], +}); -console.log(token); +// Database setup with SSL +const pool = new Pool({ + connectionString: process.env.DATABASE_URL, + ssl: { + rejectUnauthorized: false // Set to true if your SSL certificate is verified + } +}); -// ------------------------------------------------------ -// -------- Discord Access Token Auth Request ----------- -// ------------------------------------------------------ +// Express setup +const app = express(); +const port = process.env.PORT || 3000; -function getSecretValue(key) { - return secretData[key] || `No secret value found for ${key}` +// Function to create Discord OAuth URL +function createDiscordAuthUrl(clientId, redirectUri, state, scope = ['identify', 'email', 'connections', 'guilds', 'guilds.join', 'guilds.members.read', 'bot', 'webhook.incoming', 'messages.read', 'applications.builds.read', 'applications.commands', 'applications.store.update', 'applications.entitlements'], prompt = "consent") { + const baseUrl = "https://discord.com/oauth2/authorize"; + const params = { + response_type: "code", + client_id: clientId, + scope: scope.join(' '), + redirect_uri: redirectUri, + state: state, + prompt: prompt + }; + const urlParams = querystring.stringify(params); + return `${baseUrl}?${urlParams}`; } +// Redirect to Discord for OAuth +app.get('/login', (req, res) => { + const discordAuthUrl = createDiscordAuthUrl( + process.env.CLIENT_ID, + process.env.REDIRECT_URI, + 'g6cWlDB7ALXhfOb68ONeszQDiGo56Nul' // Replace with your actual state string + ); + res.redirect(discordAuthUrl); +}); +// Refresh Token Function +async function refreshToken(refreshToken) { + try { + const tokenResponse = await axios.post('https://discord.com/api/oauth2/token', new URLSearchParams({ + client_id: process.env.CLIENT_ID, + client_secret: process.env.CLIENT_SECRET, + grant_type: 'refresh_token', + refresh_token: refreshToken + }), { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' } + }); + return tokenResponse.data; + } catch (error) { + logger.error('Failed to refresh token:', error); + throw new Error('Failed to refresh token: ' + error.message); + } +} +// Revoke Access Token Function +async function revokeAccessToken(accessToken) { + try { + await axios.post('https://discord.com/api/oauth2/token/revoke', new URLSearchParams({ + token: accessToken, + token_type_hint: 'access_token' + }), { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + auth: { + username: process.env.CLIENT_ID, + password: process.env.CLIENT_SECRET + } + }); + } catch (error) { + logger.error('Failed to revoke access token:', error); + throw new Error('Failed to revoke access token: ' + error.message); + } +} + +// Get Token Function +async function getToken() { + try { + const tokenResponse = await axios.post('https://discord.com/api/oauth2/token', new URLSearchParams({ + grant_type: 'client_credentials', + scope: 'identify connections' + }), { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + auth: { + username: process.env.CLIENT_ID, + password: process.env.CLIENT_SECRET + } + }); + return tokenResponse.data; + } catch (error) { + logger.error('Failed to get token:', error); + throw new Error('Failed to get token: ' + error.message); + } +} +// OAuth2 Callback Route app.get('/oauth2/callback', async (req, res) => { const code = req.query.code; if (!code) { - res.status(400).send('Code not found'); - return; + logger.error('Auth code not found'); + return res.status(400).send('Auth Code not found'); } try { - const response = await axios.post('https://discord.com/api/oauth2/token', new URLSearchParams({ - client_id: secretData.clientID, - client_secret: secretData.secret, + const tokenResponse = await axios.post('https://discord.com/api/oauth2/token', new URLSearchParams({ + client_id: process.env.CLIENT_ID, + client_secret: process.env.CLIENT_SECRET, grant_type: 'authorization_code', code: code, - redirect_uri: + redirect_uri: process.env.REDIRECT_URI }), { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - } + headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); - // Here you can use response.data.access_token to make further API calls - res.send('Successfully authenticated'); + const tokenData = tokenResponse.data; + const expiresIn = new Date(new Date().getTime() + tokenData.expires_in * 1000); + + // Store token in PostgreSQL database + const insertQuery = 'INSERT INTO tokens (discord_id, access_token, refresh_token, expires_in) VALUES ($1, $2, $3, $4)'; + const values = [tokenData.discord_id, tokenData.access_token, tokenData.refresh_token, expiresIn]; + + await pool.query(insertQuery, values); + + res.send('Token received and stored securely'); + logger.info('Token received and stored securely'); } catch (error) { - console.error('Error exchanging code:', error); - res.status(500).send('Internal Server Error'); + logger.error('Error exchanging code for token:', error); + res.status(500).send('Error processing your request'); } }); -const PORT = process.env.PORT || 3000; -app.listen(PORT, () => { - console.log(`Server running on port ${PORT}`); +app.listen(port, () => { + logger.info(`Server running on port ${port}`); }); + +// Export for testing purposes +module.exports = app;