summary refs log tree commit diff
path: root/src/api
diff options
context:
space:
mode:
authorPuyodead1 <puyodead@proton.me>2022-12-23 18:34:36 -0500
committerPuyodead1 <puyodead@proton.me>2023-03-18 19:27:39 -0400
commit0db1fa5f0b2b9b357c1f96178c0e5df7858a99ab (patch)
treeb045eee5f984a40ae47413bad2458cf65eff3c8e /src/api
parentDon't try to upload entire config for each connection loaded (diff)
downloadserver-0db1fa5f0b2b9b357c1f96178c0e5df7858a99ab.tar.xz
Refreshable connections, refactoring, access-token endpoint
- Aded /users/@me/connections/:connection_name/:connection_id/access-token
- Replaced `access_token` property on ConnectedAccount with `token_data` object for refreshing tokens
- Made a common interface for connection things like ComonOAuthTokenResponse
- Added `RefreshableConnection` class
- Added token refresh to Spotify connection (disabled)
Diffstat (limited to 'src/api')
-rw-r--r--src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts84
-rw-r--r--src/api/routes/users/@me/connections/index.ts2
2 files changed, 85 insertions, 1 deletions
diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts
new file mode 100644
index 00000000..8d51a770
--- /dev/null
+++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts
@@ -0,0 +1,84 @@
+import { route } from "@fosscord/api";
+import {
+	ApiError,
+	ConnectedAccount,
+	ConnectionStore,
+	DiscordApiErrors,
+	FieldErrors,
+} from "@fosscord/util";
+import { Request, Response, Router } from "express";
+import RefreshableConnection from "../../../../../../../util/connections/RefreshableConnection";
+const router = Router();
+
+// TODO: this route is only used for spotify, twitch, and youtube. (battlenet seems to be able to PUT, maybe others also)
+
+// spotify is disabled here because it cant be used
+const ALLOWED_CONNECTIONS = ["twitch", "youtube"];
+
+router.get("/", route({}), async (req: Request, res: Response) => {
+	// TODO: get the current access token or refresh it if it's expired
+	const { connection_name, connection_id } = req.params;
+
+	const connection = ConnectionStore.connections.get(connection_id);
+
+	if (!ALLOWED_CONNECTIONS.includes(connection_name) || !connection)
+		throw FieldErrors({
+			provider_id: {
+				code: "BASE_TYPE_CHOICES",
+				message: req.t("common:field.BASE_TYPE_CHOICES", {
+					types: ALLOWED_CONNECTIONS.join(", "),
+				}),
+			},
+		});
+
+	if (!connection.settings.enabled)
+		throw FieldErrors({
+			provider_id: {
+				message: "This connection has been disabled server-side.",
+			},
+		});
+
+	const connectedAccount = await ConnectedAccount.findOne({
+		where: {
+			type: connection_name,
+			id: connection_id,
+			user_id: req.user_id,
+		},
+		select: [
+			"external_id",
+			"type",
+			"name",
+			"verified",
+			"visibility",
+			"show_activity",
+			"revoked",
+			"token_data",
+			"friend_sync",
+			"integrations",
+		],
+	});
+	if (!connectedAccount) throw DiscordApiErrors.UNKNOWN_CONNECTION;
+	if (connectedAccount.revoked)
+		throw new ApiError("Connection revoked", 0, 400);
+	if (!connectedAccount.token_data)
+		throw new ApiError("No token data", 0, 400);
+
+	let access_token = connectedAccount.token_data.access_token;
+	const { expires_at, expires_in } = connectedAccount.token_data;
+
+	if (expires_at && expires_at < Date.now()) {
+		if (!(connection instanceof RefreshableConnection))
+			throw new ApiError("Access token expired", 0, 400);
+		const tokenData = await connection.refresh(connectedAccount);
+		access_token = tokenData.access_token;
+	} else if (expires_in && expires_in < Date.now()) {
+		if (!(connection instanceof RefreshableConnection))
+			throw new ApiError("Access token expired", 0, 400);
+		const tokenData = await connection.refresh(connectedAccount);
+		access_token = tokenData.access_token;
+	}
+
+	res.json({ access_token });
+});
+
+export default router;
diff --git a/src/api/routes/users/@me/connections/index.ts b/src/api/routes/users/@me/connections/index.ts
index a5041be1..8e762f19 100644
--- a/src/api/routes/users/@me/connections/index.ts
+++ b/src/api/routes/users/@me/connections/index.ts
@@ -35,7 +35,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 			"visibility",
 			"show_activity",
 			"revoked",
-			"access_token",
+			"token_data",
 			"friend_sync",
 			"integrations",
 		],