diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts
index 65ee8ab9..4fdfccb1 100644
--- a/src/connections/BattleNet/index.ts
+++ b/src/connections/BattleNet/index.ts
@@ -19,10 +19,10 @@
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
+ Connection,
ConnectionCallbackSchema,
ConnectionLoader,
DiscordApiErrors,
- Connection,
} from "@spacebar/util";
import wretch from "wretch";
import { BattleNetSettings } from "./BattleNetSettings";
@@ -47,17 +47,21 @@ export default class BattleNetConnection extends Connection {
settings: BattleNetSettings = new BattleNetSettings();
init(): void {
- this.settings = ConnectionLoader.getConnectionConfig(
- this.id,
- this.settings,
- ) as BattleNetSettings;
+ const settings =
+ ConnectionLoader.getConnectionConfig<BattleNetSettings>(
+ this.id,
+ this.settings,
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("redirect_uri", this.getRedirectUri());
url.searchParams.append("scope", this.scopes.join(" "));
url.searchParams.append("state", state);
@@ -85,8 +89,8 @@ export default class BattleNetConnection extends Connection {
new URLSearchParams({
grant_type: "authorization_code",
code: code,
- client_id: this.settings.clientId!,
- client_secret: this.settings.clientSecret!,
+ client_id: this.settings.clientId as string,
+ client_secret: this.settings.clientSecret as string,
redirect_uri: this.getRedirectUri(),
}),
)
@@ -115,8 +119,11 @@ export default class BattleNetConnection extends Connection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userInfo = await this.getUser(tokenData.access_token);
const exists = await this.hasConnection(userId, userInfo.id.toString());
diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts
index 098ce999..731086f1 100644
--- a/src/connections/Discord/index.ts
+++ b/src/connections/Discord/index.ts
@@ -19,10 +19,10 @@
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
+ Connection,
ConnectionCallbackSchema,
ConnectionLoader,
DiscordApiErrors,
- Connection,
} from "@spacebar/util";
import wretch from "wretch";
import { DiscordSettings } from "./DiscordSettings";
@@ -43,10 +43,13 @@ export default class DiscordConnection extends Connection {
settings: DiscordSettings = new DiscordSettings();
init(): void {
- this.settings = ConnectionLoader.getConnectionConfig(
+ const settings = ConnectionLoader.getConnectionConfig<DiscordSettings>(
this.id,
this.settings,
- ) as DiscordSettings;
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -54,7 +57,7 @@ export default class DiscordConnection extends Connection {
const url = new URL(this.authorizeUrl);
url.searchParams.append("state", state);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("scope", this.scopes.join(" "));
url.searchParams.append("response_type", "code");
// controls whether, on repeated authorizations, the consent screen is shown
@@ -82,8 +85,8 @@ export default class DiscordConnection extends Connection {
})
.body(
new URLSearchParams({
- client_id: this.settings.clientId!,
- client_secret: this.settings.clientSecret!,
+ client_id: this.settings.clientId as string,
+ client_secret: this.settings.clientSecret as string,
grant_type: "authorization_code",
code: code,
redirect_uri: this.getRedirectUri(),
@@ -114,8 +117,11 @@ export default class DiscordConnection extends Connection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userInfo = await this.getUser(tokenData.access_token);
const exists = await this.hasConnection(userId, userInfo.id);
diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts
index 8521a6f3..e5b2d336 100644
--- a/src/connections/EpicGames/index.ts
+++ b/src/connections/EpicGames/index.ts
@@ -19,10 +19,10 @@
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
+ Connection,
ConnectionCallbackSchema,
ConnectionLoader,
DiscordApiErrors,
- Connection,
} from "@spacebar/util";
import wretch from "wretch";
import { EpicGamesSettings } from "./EpicGamesSettings";
@@ -53,17 +53,21 @@ export default class EpicGamesConnection extends Connection {
settings: EpicGamesSettings = new EpicGamesSettings();
init(): void {
- this.settings = ConnectionLoader.getConnectionConfig(
- this.id,
- this.settings,
- ) as EpicGamesSettings;
+ const settings =
+ ConnectionLoader.getConnectionConfig<EpicGamesSettings>(
+ this.id,
+ this.settings,
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("redirect_uri", this.getRedirectUri());
url.searchParams.append("response_type", "code");
url.searchParams.append("scope", this.scopes.join(" "));
@@ -127,8 +131,11 @@ export default class EpicGamesConnection extends Connection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userInfo = await this.getUser(tokenData.access_token);
const exists = await this.hasConnection(userId, userInfo[0].accountId);
diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts
index f3c16cf0..2bf26f34 100644
--- a/src/connections/Facebook/index.ts
+++ b/src/connections/Facebook/index.ts
@@ -19,10 +19,10 @@
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
+ Connection,
ConnectionCallbackSchema,
ConnectionLoader,
DiscordApiErrors,
- Connection,
} from "@spacebar/util";
import wretch from "wretch";
import { FacebookSettings } from "./FacebookSettings";
@@ -52,17 +52,20 @@ export default class FacebookConnection extends Connection {
settings: FacebookSettings = new FacebookSettings();
init(): void {
- this.settings = ConnectionLoader.getConnectionConfig(
+ const settings = ConnectionLoader.getConnectionConfig<FacebookSettings>(
this.id,
this.settings,
- ) as FacebookSettings;
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("redirect_uri", this.getRedirectUri());
url.searchParams.append("state", state);
url.searchParams.append("response_type", "code");
@@ -73,8 +76,11 @@ export default class FacebookConnection extends Connection {
getTokenUrl(code: string): string {
const url = new URL(this.tokenUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
- url.searchParams.append("client_secret", this.settings.clientSecret!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
+ url.searchParams.append(
+ "client_secret",
+ this.settings.clientSecret as string,
+ );
url.searchParams.append("code", code);
url.searchParams.append("redirect_uri", this.getRedirectUri());
return url.toString();
@@ -118,8 +124,11 @@ export default class FacebookConnection extends Connection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userInfo = await this.getUser(tokenData.access_token);
const exists = await this.hasConnection(userId, userInfo.id);
diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts
index 101b205c..25e5f89f 100644
--- a/src/connections/GitHub/index.ts
+++ b/src/connections/GitHub/index.ts
@@ -19,10 +19,10 @@
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
+ Connection,
ConnectionCallbackSchema,
ConnectionLoader,
DiscordApiErrors,
- Connection,
} from "@spacebar/util";
import wretch from "wretch";
import { GitHubSettings } from "./GitHubSettings";
@@ -42,17 +42,20 @@ export default class GitHubConnection extends Connection {
settings: GitHubSettings = new GitHubSettings();
init(): void {
- this.settings = ConnectionLoader.getConnectionConfig(
+ const settings = ConnectionLoader.getConnectionConfig<GitHubSettings>(
this.id,
this.settings,
- ) as GitHubSettings;
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("redirect_uri", this.getRedirectUri());
url.searchParams.append("scope", this.scopes.join(" "));
url.searchParams.append("state", state);
@@ -61,8 +64,11 @@ export default class GitHubConnection extends Connection {
getTokenUrl(code: string): string {
const url = new URL(this.tokenUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
- url.searchParams.append("client_secret", this.settings.clientSecret!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
+ url.searchParams.append(
+ "client_secret",
+ this.settings.clientSecret as string,
+ );
url.searchParams.append("code", code);
return url.toString();
}
@@ -105,8 +111,11 @@ export default class GitHubConnection extends Connection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userInfo = await this.getUser(tokenData.access_token);
const exists = await this.hasConnection(userId, userInfo.id.toString());
diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts
index 6194d251..149cce02 100644
--- a/src/connections/Reddit/index.ts
+++ b/src/connections/Reddit/index.ts
@@ -19,10 +19,10 @@
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
+ Connection,
ConnectionCallbackSchema,
ConnectionLoader,
DiscordApiErrors,
- Connection,
} from "@spacebar/util";
import wretch from "wretch";
import { RedditSettings } from "./RedditSettings";
@@ -54,17 +54,20 @@ export default class RedditConnection extends Connection {
settings: RedditSettings = new RedditSettings();
init(): void {
- this.settings = ConnectionLoader.getConnectionConfig(
+ const settings = ConnectionLoader.getConnectionConfig<RedditSettings>(
this.id,
this.settings,
- ) as RedditSettings;
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("redirect_uri", this.getRedirectUri());
url.searchParams.append("response_type", "code");
url.searchParams.append("scope", this.scopes.join(" "));
@@ -124,8 +127,11 @@ export default class RedditConnection extends Connection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userInfo = await this.getUser(tokenData.access_token);
const exists = await this.hasConnection(userId, userInfo.id.toString());
diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts
index 50f14a38..ece404d8 100644
--- a/src/connections/Spotify/index.ts
+++ b/src/connections/Spotify/index.ts
@@ -63,17 +63,20 @@ export default class SpotifyConnection extends RefreshableConnection {
* So to prevent spamming the spotify api we disable the ability to refresh.
*/
this.refreshEnabled = false;
- this.settings = ConnectionLoader.getConnectionConfig(
+ const settings = ConnectionLoader.getConnectionConfig<SpotifySettings>(
this.id,
this.settings,
- ) as SpotifySettings;
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("redirect_uri", this.getRedirectUri());
url.searchParams.append("response_type", "code");
url.searchParams.append("scope", this.scopes.join(" "));
@@ -98,7 +101,9 @@ export default class SpotifyConnection extends RefreshableConnection {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
- `${this.settings.clientId!}:${this.settings.clientSecret!}`,
+ `${this.settings.clientId as string}:${
+ this.settings.clientSecret as string
+ }`,
).toString("base64")}`,
})
.body(
@@ -129,7 +134,9 @@ export default class SpotifyConnection extends RefreshableConnection {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
- `${this.settings.clientId!}:${this.settings.clientSecret!}`,
+ `${this.settings.clientId as string}:${
+ this.settings.clientSecret as string
+ }`,
).toString("base64")}`,
})
.body(
@@ -169,8 +176,11 @@ export default class SpotifyConnection extends RefreshableConnection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userInfo = await this.getUser(tokenData.access_token);
const exists = await this.hasConnection(userId, userInfo.id);
diff --git a/src/connections/Twitch/index.ts b/src/connections/Twitch/index.ts
index f9412a17..9a6cea35 100644
--- a/src/connections/Twitch/index.ts
+++ b/src/connections/Twitch/index.ts
@@ -55,17 +55,20 @@ export default class TwitchConnection extends RefreshableConnection {
settings: TwitchSettings = new TwitchSettings();
init(): void {
- this.settings = ConnectionLoader.getConnectionConfig(
+ const settings = ConnectionLoader.getConnectionConfig<TwitchSettings>(
this.id,
this.settings,
- ) as TwitchSettings;
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("redirect_uri", this.getRedirectUri());
url.searchParams.append("response_type", "code");
url.searchParams.append("scope", this.scopes.join(" "));
@@ -94,8 +97,8 @@ export default class TwitchConnection extends RefreshableConnection {
new URLSearchParams({
grant_type: "authorization_code",
code: code,
- client_id: this.settings.clientId!,
- client_secret: this.settings.clientSecret!,
+ client_id: this.settings.clientId as string,
+ client_secret: this.settings.clientSecret as string,
redirect_uri: this.getRedirectUri(),
}),
)
@@ -124,8 +127,8 @@ export default class TwitchConnection extends RefreshableConnection {
.body(
new URLSearchParams({
grant_type: "refresh_token",
- client_id: this.settings.clientId!,
- client_secret: this.settings.clientSecret!,
+ client_id: this.settings.clientId as string,
+ client_secret: this.settings.clientSecret as string,
refresh_token: refresh_token,
}),
)
@@ -148,7 +151,7 @@ export default class TwitchConnection extends RefreshableConnection {
return wretch(url.toString())
.headers({
Authorization: `Bearer ${token}`,
- "Client-Id": this.settings.clientId!,
+ "Client-Id": this.settings.clientId as string,
})
.get()
.json<TwitchConnectionUserResponse>()
@@ -161,8 +164,11 @@ export default class TwitchConnection extends RefreshableConnection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userInfo = await this.getUser(tokenData.access_token);
const exists = await this.hasConnection(userId, userInfo.data[0].id);
diff --git a/src/connections/Twitter/index.ts b/src/connections/Twitter/index.ts
index 4526fdf5..62fd7da1 100644
--- a/src/connections/Twitter/index.ts
+++ b/src/connections/Twitter/index.ts
@@ -55,17 +55,20 @@ export default class TwitterConnection extends RefreshableConnection {
settings: TwitterSettings = new TwitterSettings();
init(): void {
- this.settings = ConnectionLoader.getConnectionConfig(
+ const settings = ConnectionLoader.getConnectionConfig<TwitterSettings>(
this.id,
this.settings,
- ) as TwitterSettings;
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("redirect_uri", this.getRedirectUri());
url.searchParams.append("response_type", "code");
url.searchParams.append("scope", this.scopes.join(" "));
@@ -92,14 +95,16 @@ export default class TwitterConnection extends RefreshableConnection {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
- `${this.settings.clientId!}:${this.settings.clientSecret!}`,
+ `${this.settings.clientId as string}:${
+ this.settings.clientSecret as string
+ }`,
).toString("base64")}`,
})
.body(
new URLSearchParams({
grant_type: "authorization_code",
code: code,
- client_id: this.settings.clientId!,
+ client_id: this.settings.clientId as string,
redirect_uri: this.getRedirectUri(),
code_verifier: "challenge", // TODO: properly use PKCE challenge
}),
@@ -126,14 +131,16 @@ export default class TwitterConnection extends RefreshableConnection {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
- `${this.settings.clientId!}:${this.settings.clientSecret!}`,
+ `${this.settings.clientId as string}:${
+ this.settings.clientSecret as string
+ }`,
).toString("base64")}`,
})
.body(
new URLSearchParams({
grant_type: "refresh_token",
refresh_token,
- client_id: this.settings.clientId!,
+ client_id: this.settings.clientId as string,
redirect_uri: this.getRedirectUri(),
code_verifier: "challenge", // TODO: properly use PKCE challenge
}),
@@ -163,8 +170,11 @@ export default class TwitterConnection extends RefreshableConnection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userInfo = await this.getUser(tokenData.access_token);
const exists = await this.hasConnection(userId, userInfo.data.id);
diff --git a/src/connections/Xbox/index.ts b/src/connections/Xbox/index.ts
index 3df09e27..935ff7ab 100644
--- a/src/connections/Xbox/index.ts
+++ b/src/connections/Xbox/index.ts
@@ -19,10 +19,10 @@
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
+ Connection,
ConnectionCallbackSchema,
ConnectionLoader,
DiscordApiErrors,
- Connection,
} from "@spacebar/util";
import wretch from "wretch";
import { XboxSettings } from "./XboxSettings";
@@ -62,17 +62,20 @@ export default class XboxConnection extends Connection {
settings: XboxSettings = new XboxSettings();
init(): void {
- this.settings = ConnectionLoader.getConnectionConfig(
+ const settings = ConnectionLoader.getConnectionConfig<XboxSettings>(
this.id,
this.settings,
- ) as XboxSettings;
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("redirect_uri", this.getRedirectUri());
url.searchParams.append("response_type", "code");
url.searchParams.append("scope", this.scopes.join(" "));
@@ -124,14 +127,16 @@ export default class XboxConnection extends Connection {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
- `${this.settings.clientId!}:${this.settings.clientSecret!}`,
+ `${this.settings.clientId as string}:${
+ this.settings.clientSecret as string
+ }`,
).toString("base64")}`,
})
.body(
new URLSearchParams({
grant_type: "authorization_code",
code: code,
- client_id: this.settings.clientId!,
+ client_id: this.settings.clientId as string,
redirect_uri: this.getRedirectUri(),
scope: this.scopes.join(" "),
}),
@@ -174,8 +179,11 @@ export default class XboxConnection extends Connection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userToken = await this.getUserToken(tokenData.access_token);
const userInfo = await this.getUser(userToken);
diff --git a/src/connections/Youtube/index.ts b/src/connections/Youtube/index.ts
index faab44c5..844803cf 100644
--- a/src/connections/Youtube/index.ts
+++ b/src/connections/Youtube/index.ts
@@ -19,10 +19,10 @@
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
+ Connection,
ConnectionCallbackSchema,
ConnectionLoader,
DiscordApiErrors,
- Connection,
} from "@spacebar/util";
import wretch from "wretch";
import { YoutubeSettings } from "./YoutubeSettings";
@@ -62,17 +62,20 @@ export default class YoutubeConnection extends Connection {
settings: YoutubeSettings = new YoutubeSettings();
init(): void {
- this.settings = ConnectionLoader.getConnectionConfig(
+ const settings = ConnectionLoader.getConnectionConfig<YoutubeSettings>(
this.id,
this.settings,
- ) as YoutubeSettings;
+ );
+
+ if (settings.enabled && (!settings.clientId || !settings.clientSecret))
+ throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
- url.searchParams.append("client_id", this.settings.clientId!);
+ url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append("redirect_uri", this.getRedirectUri());
url.searchParams.append("response_type", "code");
url.searchParams.append("scope", this.scopes.join(" "));
@@ -101,8 +104,8 @@ export default class YoutubeConnection extends Connection {
new URLSearchParams({
grant_type: "authorization_code",
code: code,
- client_id: this.settings.clientId!,
- client_secret: this.settings.clientSecret!,
+ client_id: this.settings.clientId as string,
+ client_secret: this.settings.clientSecret as string,
redirect_uri: this.getRedirectUri(),
}),
)
@@ -131,8 +134,11 @@ export default class YoutubeConnection extends Connection {
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
- const userId = this.getUserId(params.state);
- const tokenData = await this.exchangeCode(params.state, params.code!);
+ const { state, code } = params;
+ if (!code) throw new Error("No code provided");
+
+ const userId = this.getUserId(state);
+ const tokenData = await this.exchangeCode(state, code);
const userInfo = await this.getUser(tokenData.access_token);
const exists = await this.hasConnection(userId, userInfo.items[0].id);
diff --git a/src/util/connections/ConnectionLoader.ts b/src/util/connections/ConnectionLoader.ts
index 6b27baec..e9dc6973 100644
--- a/src/util/connections/ConnectionLoader.ts
+++ b/src/util/connections/ConnectionLoader.ts
@@ -16,9 +16,9 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+import { Connection } from "@spacebar/util";
import fs from "fs";
import path from "path";
-import { Connection } from "@spacebar/util";
import { ConnectionConfig } from "./ConnectionConfig";
import { ConnectionStore } from "./ConnectionStore";
@@ -48,8 +48,7 @@ export class ConnectionLoader {
});
}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- public static getConnectionConfig(id: string, defaults?: any): any {
+ public static getConnectionConfig<T>(id: string, defaults?: unknown): T {
let cfg = ConnectionConfig.get()[id];
if (defaults) {
if (cfg) cfg = Object.assign({}, defaults, cfg);
@@ -70,8 +69,7 @@ export class ConnectionLoader {
public static async setConnectionConfig(
id: string,
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- config: Partial<any>,
+ config: Partial<unknown>,
): Promise<void> {
if (!config)
console.warn(`[Connections/WARN] ${id} tried to set config=null!`);
diff --git a/src/util/connections/RefreshableConnection.ts b/src/util/connections/RefreshableConnection.ts
index eaa88c1b..88ad8dab 100644
--- a/src/util/connections/RefreshableConnection.ts
+++ b/src/util/connections/RefreshableConnection.ts
@@ -25,6 +25,7 @@ import { Connection } from "./Connection";
*/
export abstract class RefreshableConnection extends Connection {
refreshEnabled = true;
+
/**
* Refreshes the token for a connected account.
* @param connectedAccount The connected account to refresh
|