diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts
index f7d08cbe8..30488e3c9 100644
--- a/src/connections/BattleNet/index.ts
+++ b/src/connections/BattleNet/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
-import { BattleNetSettings } from "./BattleNetSettings";
+import { GenericOAuthSettings as BattleNetSettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
interface BattleNetConnectionUser {
@@ -34,6 +34,10 @@ interface BattleNetConnectionUser {
export default class BattleNetConnection extends Connection {
public readonly id = "battlenet";
+ public readonly friendlyName = "Battle.net";
+ public readonly setupUrl = "(missing - contributions welcome)";
+ public readonly requiredScopes = [];
+
public readonly authorizeUrl = "https://oauth.battle.net/authorize";
public readonly tokenUrl = "https://oauth.battle.net/token";
public readonly userInfoUrl = "https://us.battle.net/oauth/userinfo";
@@ -46,6 +50,10 @@ export default class BattleNetConnection extends Connection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
+
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/connections/Discord/DiscordSettings.ts b/src/connections/Discord/DiscordSettings.ts
deleted file mode 100644
index af0b8d6c9..000000000
--- a/src/connections/Discord/DiscordSettings.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-export class DiscordSettings {
- enabled: boolean = false;
- clientId: string | null = null;
- clientSecret: string | null = null;
-}
diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts
index f209a81bd..5a15f0978 100644
--- a/src/connections/Discord/index.ts
+++ b/src/connections/Discord/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
-import { DiscordSettings } from "./DiscordSettings";
+import { GenericOAuthSettings as DiscordSettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
interface UserResponse {
@@ -30,6 +30,10 @@ interface UserResponse {
export default class DiscordConnection extends Connection {
public readonly id = "discord";
+ public readonly friendlyName = "Discord";
+ public readonly setupUrl = "https://discord.com/developers/applications";
+ public readonly requiredScopes = ["identify"];
+
public readonly authorizeUrl = "https://discord.com/api/oauth2/authorize";
public readonly tokenUrl = "https://discord.com/api/oauth2/token";
public readonly userInfoUrl = "https://discord.com/api/users/@me";
@@ -42,6 +46,10 @@ export default class DiscordConnection extends Connection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
+
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/connections/EpicGames/EpicGamesSettings.ts b/src/connections/EpicGames/EpicGamesSettings.ts
deleted file mode 100644
index fbe5c7a32..000000000
--- a/src/connections/EpicGames/EpicGamesSettings.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-export class EpicGamesSettings {
- enabled: boolean = false;
- clientId: string | null = null;
- clientSecret: string | null = null;
-}
diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts
index 959192e64..5fc2701f4 100644
--- a/src/connections/EpicGames/index.ts
+++ b/src/connections/EpicGames/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
-import { EpicGamesSettings } from "./EpicGamesSettings";
+import { GenericOAuthSettings as EpicGamesSettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
export interface UserResponse {
@@ -38,6 +38,10 @@ export interface EpicTokenResponse extends ConnectedAccountCommonOAuthTokenRespo
export default class EpicGamesConnection extends Connection {
public readonly id = "epicgames";
+ public readonly friendlyName = "Epic Games";
+ public readonly setupUrl = "https://dev.epicgames.com/portal";
+ public readonly requiredScopes = [];
+
public readonly authorizeUrl = "https://www.epicgames.com/id/authorize";
public readonly tokenUrl = "https://api.epicgames.dev/epic/oauth/v1/token";
public readonly userInfoUrl = "https://api.epicgames.dev/epic/id/v1/accounts";
@@ -50,6 +54,9 @@ export default class EpicGamesConnection extends Connection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/connections/Facebook/FacebookSettings.ts b/src/connections/Facebook/FacebookSettings.ts
deleted file mode 100644
index f130358a1..000000000
--- a/src/connections/Facebook/FacebookSettings.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-export class FacebookSettings {
- enabled: boolean = false;
- clientId: string | null = null;
- clientSecret: string | null = null;
-}
diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts
index 29317c2e6..3abd5669e 100644
--- a/src/connections/Facebook/index.ts
+++ b/src/connections/Facebook/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
-import { FacebookSettings } from "./FacebookSettings";
+import { GenericOAuthSettings as FacebookSettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
export interface FacebookErrorResponse {
@@ -37,6 +37,10 @@ interface UserResponse {
export default class FacebookConnection extends Connection {
public readonly id = "facebook";
+ public readonly friendlyName = "Facebook";
+ public readonly setupUrl = "(missing - contributions welcome)";
+ public readonly requiredScopes = [];
+
public readonly authorizeUrl = "https://www.facebook.com/v14.0/dialog/oauth";
public readonly tokenUrl = "https://graph.facebook.com/v14.0/oauth/access_token";
public readonly userInfoUrl = "https://graph.facebook.com/v14.0/me";
@@ -49,6 +53,10 @@ export default class FacebookConnection extends Connection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
+
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/connections/BattleNet/BattleNetSettings.ts b/src/connections/GenericOAuthSettings.ts
similarity index 89%
rename from src/connections/BattleNet/BattleNetSettings.ts
rename to src/connections/GenericOAuthSettings.ts
index 661fdeb8e..d4ccb354e 100644
--- a/src/connections/BattleNet/BattleNetSettings.ts
+++ b/src/connections/GenericOAuthSettings.ts
@@ -1,22 +1,22 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
+ Copyright (C) 2026 Spacebar and Spacebar Contributors
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
-
+
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-export class BattleNetSettings {
+export class GenericOAuthSettings {
enabled: boolean = false;
clientId: string | null = null;
clientSecret: string | null = null;
diff --git a/src/connections/GitHub/GitHubSettings.ts b/src/connections/GitHub/GitHubSettings.ts
deleted file mode 100644
index f744a77f0..000000000
--- a/src/connections/GitHub/GitHubSettings.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-export class GitHubSettings {
- enabled: boolean = false;
- clientId: string | null = null;
- clientSecret: string | null = null;
-}
diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts
index df64912ae..a5e0f7041 100644
--- a/src/connections/GitHub/index.ts
+++ b/src/connections/GitHub/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
-import { GitHubSettings } from "./GitHubSettings";
+import { GenericOAuthSettings as GitHubSettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
interface UserResponse {
@@ -29,6 +29,10 @@ interface UserResponse {
export default class GitHubConnection extends Connection {
public readonly id = "github";
+ public friendlyName = "GitHub";
+ public setupUrl = "https://github.com/settings/developers";
+ public requiredScopes: string[];
+
public readonly authorizeUrl = "https://github.com/login/oauth/authorize";
public readonly tokenUrl = "https://github.com/login/oauth/access_token";
public readonly userInfoUrl = "https://api.github.com/user";
@@ -41,6 +45,10 @@ export default class GitHubConnection extends Connection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
+
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/connections/Reddit/RedditSettings.ts b/src/connections/Reddit/RedditSettings.ts
deleted file mode 100644
index 083af8e60..000000000
--- a/src/connections/Reddit/RedditSettings.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-export class RedditSettings {
- enabled: boolean = false;
- clientId: string | null = null;
- clientSecret: string | null = null;
-}
diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts
index 781e097a1..92f3737e1 100644
--- a/src/connections/Reddit/index.ts
+++ b/src/connections/Reddit/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
-import { RedditSettings } from "./RedditSettings";
+import { GenericOAuthSettings as RedditSettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
export interface UserResponse {
@@ -41,6 +41,10 @@ export interface ErrorResponse {
export default class RedditConnection extends Connection {
public readonly id = "reddit";
+ public friendlyName = "Reddit";
+ public setupUrl = "https://www.reddit.com/prefs/apps";
+ public requiredScopes = []; // Does not seem to offer platform-side scope controls
+
public readonly authorizeUrl = "https://www.reddit.com/api/v1/authorize";
public readonly tokenUrl = "https://www.reddit.com/api/v1/access_token";
public readonly userInfoUrl = "https://oauth.reddit.com/api/v1/me";
@@ -53,6 +57,10 @@ export default class RedditConnection extends Connection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
+
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/connections/Spotify/SpotifySettings.ts b/src/connections/Spotify/SpotifySettings.ts
deleted file mode 100644
index e2db48625..000000000
--- a/src/connections/Spotify/SpotifySettings.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-export class SpotifySettings {
- enabled: boolean = false;
- clientId: string | null = null;
- clientSecret: string | null = null;
-}
diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts
index 2186396bb..e64626b17 100644
--- a/src/connections/Spotify/index.ts
+++ b/src/connections/Spotify/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, ConnectionLoader, DiscordApiErrors, RefreshableConnection } from "@spacebar/util";
import wretch from "wretch";
-import { SpotifySettings } from "./SpotifySettings";
+import { GenericOAuthSettings as SpotifySettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
export interface UserResponse {
@@ -40,6 +40,10 @@ export interface ErrorResponse {
export default class SpotifyConnection extends RefreshableConnection {
public readonly id = "spotify";
+ public friendlyName = "Spotify";
+ public setupUrl = "https://developer.spotify.com";
+ public requiredScopes = ["Requires instance admin to have spotify premium"];
+
public readonly authorizeUrl = "https://accounts.spotify.com/authorize";
public readonly tokenUrl = "https://accounts.spotify.com/api/token";
public readonly userInfoUrl = "https://api.spotify.com/v1/me";
@@ -58,6 +62,10 @@ export default class SpotifyConnection extends RefreshableConnection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
+
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/connections/Twitch/TwitchSettings.ts b/src/connections/Twitch/TwitchSettings.ts
deleted file mode 100644
index fcd0a0d95..000000000
--- a/src/connections/Twitch/TwitchSettings.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-export class TwitchSettings {
- enabled: boolean = false;
- clientId: string | null = null;
- clientSecret: string | null = null;
-}
diff --git a/src/connections/Twitch/index.ts b/src/connections/Twitch/index.ts
index 5952caf1a..116b31921 100644
--- a/src/connections/Twitch/index.ts
+++ b/src/connections/Twitch/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, ConnectionLoader, DiscordApiErrors, RefreshableConnection } from "@spacebar/util";
import wretch from "wretch";
-import { TwitchSettings } from "./TwitchSettings";
+import { GenericOAuthSettings as TwitchSettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
interface TwitchConnectionUserResponse {
@@ -38,6 +38,10 @@ interface TwitchConnectionUserResponse {
export default class TwitchConnection extends RefreshableConnection {
public readonly id = "twitch";
+ public friendlyName = "Twitch.tv";
+ public setupUrl = "https://dev.twitch.tv/console/apps/create";
+ public requiredScopes: string[];
+
public readonly authorizeUrl = "https://id.twitch.tv/oauth2/authorize";
public readonly tokenUrl = "https://id.twitch.tv/oauth2/token";
public readonly userInfoUrl = "https://api.twitch.tv/helix/users";
@@ -50,6 +54,10 @@ export default class TwitchConnection extends RefreshableConnection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
+
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/connections/Twitter/TwitterSettings.ts b/src/connections/Twitter/TwitterSettings.ts
deleted file mode 100644
index f9b2f5aba..000000000
--- a/src/connections/Twitter/TwitterSettings.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-export class TwitterSettings {
- enabled: boolean = false;
- clientId: string | null = null;
- clientSecret: string | null = null;
-}
diff --git a/src/connections/Twitter/index.ts b/src/connections/Twitter/index.ts
index 3c79515be..7a56aa41c 100644
--- a/src/connections/Twitter/index.ts
+++ b/src/connections/Twitter/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, ConnectionLoader, DiscordApiErrors, RefreshableConnection } from "@spacebar/util";
import wretch from "wretch";
-import { TwitterSettings } from "./TwitterSettings";
+import { GenericOAuthSettings as TwitterSettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
interface TwitterUserResponse {
@@ -41,6 +41,10 @@ interface TwitterUserResponse {
export default class TwitterConnection extends RefreshableConnection {
public readonly id = "twitter";
+ public friendlyName = "Twitter";
+ public setupUrl = "https://console.x.com";
+ public requiredScopes = []; //no scopes nessecary
+
public readonly authorizeUrl = "https://twitter.com/i/oauth2/authorize";
public readonly tokenUrl = "https://api.twitter.com/2/oauth2/token";
public readonly userInfoUrl = "https://api.twitter.com/2/users/me?user.fields=created_at%2Cdescription%2Cid%2Cname%2Cusername%2Cverified%2Clocation%2Curl";
@@ -53,6 +57,10 @@ export default class TwitterConnection extends RefreshableConnection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
+
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/connections/Xbox/XboxSettings.ts b/src/connections/Xbox/XboxSettings.ts
deleted file mode 100644
index b7e97de30..000000000
--- a/src/connections/Xbox/XboxSettings.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-export class XboxSettings {
- enabled: boolean = false;
- clientId: string | null = null;
- clientSecret: string | null = null;
-}
diff --git a/src/connections/Xbox/index.ts b/src/connections/Xbox/index.ts
index 59d4a0054..95cd6ecb0 100644
--- a/src/connections/Xbox/index.ts
+++ b/src/connections/Xbox/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
-import { XboxSettings } from "./XboxSettings";
+import { GenericOAuthSettings as XboxSettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
interface XboxUserResponse {
@@ -45,6 +45,10 @@ interface XboxUserResponse {
export default class XboxConnection extends Connection {
public readonly id = "xbox";
+ public readonly friendlyName = "Xbox Live";
+ public readonly setupUrl = "https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade";
+ public readonly requiredScopes = []; // these are part of the URL and don't need to be assigned
+
public readonly authorizeUrl = "https://login.live.com/oauth20_authorize.srf";
public readonly tokenUrl = "https://login.live.com/oauth20_token.srf";
public readonly userInfoUrl = "https://xsts.auth.xboxlive.com/xsts/authorize";
@@ -58,6 +62,10 @@ export default class XboxConnection extends Connection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
+
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/connections/Youtube/YoutubeSettings.ts b/src/connections/Youtube/YoutubeSettings.ts
deleted file mode 100644
index b2f7c1ba8..000000000
--- a/src/connections/Youtube/YoutubeSettings.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-export class YoutubeSettings {
- enabled: boolean = false;
- clientId: string | null = null;
- clientSecret: string | null = null;
-}
diff --git a/src/connections/Youtube/index.ts b/src/connections/Youtube/index.ts
index 2db9289f3..64debb83b 100644
--- a/src/connections/Youtube/index.ts
+++ b/src/connections/Youtube/index.ts
@@ -18,7 +18,7 @@
import { ConnectedAccount, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
-import { YoutubeSettings } from "./YoutubeSettings";
+import { GenericOAuthSettings as YoutubeSettings } from "../GenericOAuthSettings";
import { ConnectedAccountCommonOAuthTokenResponse, ConnectionCallbackSchema } from "@spacebar/schemas";
interface YouTubeConnectionChannelListResult {
@@ -45,6 +45,10 @@ interface YouTubeConnectionChannelListResult {
export default class YoutubeConnection extends Connection {
public readonly id = "youtube";
+ public readonly friendlyName = "YouTube";
+ public readonly setupUrl = "https://console.cloud.google.com/apis/api/youtube.googleapis.com";
+ public readonly requiredScopes = ["/auth/youtube.readonly"];
+
public readonly authorizeUrl = "https://accounts.google.com/o/oauth2/v2/auth";
public readonly tokenUrl = "https://oauth2.googleapis.com/token";
public readonly userInfoUrl = "https://www.googleapis.com/youtube/v3/channels?mine=true&part=snippet";
@@ -57,6 +61,10 @@ export default class YoutubeConnection extends Connection {
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
+ public get isConfigured(): boolean {
+ return !!this.settings.clientId && !!this.settings.clientSecret;
+ }
+
getAuthorizationUrl(userId: string): string {
const state = this.createState(userId);
const url = new URL(this.authorizeUrl);
diff --git a/src/util/connections/Connection.ts b/src/util/connections/Connection.ts
index e48b13a11..d59341647 100644
--- a/src/util/connections/Connection.ts
+++ b/src/util/connections/Connection.ts
@@ -29,8 +29,17 @@ export abstract class Connection {
settings: { enabled: boolean };
states: Map = new Map();
+ public abstract readonly friendlyName: string;
+ public abstract readonly setupUrl: string;
+ public abstract readonly requiredScopes: string[];
+
abstract init(): void;
+ /**
+ * Returns whether a connection has all the required settings
+ */
+ public abstract get isConfigured(): boolean;
+
/**
* Generates an authorization url for the connection.
* @param userId the user id to generate the url for
diff --git a/src/util/connections/ConnectionLoader.ts b/src/util/connections/ConnectionLoader.ts
index f75b430f5..021ef3a66 100644
--- a/src/util/connections/ConnectionLoader.ts
+++ b/src/util/connections/ConnectionLoader.ts
@@ -21,6 +21,7 @@ import fs from "fs";
import path from "path";
import { ConnectionConfig } from "./ConnectionConfig";
import { ConnectionStore } from "./ConnectionStore";
+import { greenBright, redBright } from "picocolors";
const root = path.join(__dirname, "..", "..", "connections");
const connectionsLoaded = false;
@@ -44,7 +45,15 @@ export class ConnectionLoader {
ConnectionStore.connections.set(mod.id, mod);
mod.init();
- // console.log(`[Connections] Loaded connection '${mod.id}'`);
+ console.log(`[Connections] Loaded connection '${mod.id}' (${mod.friendlyName}) -`, mod.settings.enabled ? greenBright("enabled") : redBright("disabled"));
+ if (mod.settings.enabled && !mod.isConfigured) {
+ console.log(`[Connections/${mod.id}] Connection is enabled, but not configured! Users will not be able to successfully link with ${mod.friendlyName}!`);
+ if (mod.requiredScopes.length > 0) {
+ console.log(`[Connections/${mod.id}] Configuring this connection requires setting scopes, or has additional requirements:`);
+ for (const scope in mod.requiredScopes) console.log(`[Connections/${mod.id}] - ${scope}`);
+ console.log(`[Connections/${mod.id}] You can obtain the required credentials here: ${mod.setupUrl}`);
+ }
+ }
});
}