Prettier connections

This commit is contained in:
Rory&
2025-12-17 06:58:04 +01:00
parent 0f441931eb
commit 41b700e12a
11 changed files with 96 additions and 359 deletions
+6 -24
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
Connection,
ConnectionLoader,
DiscordApiErrors,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
import { BattleNetSettings } from "./BattleNetSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
interface BattleNetConnectionUser {
sub: string;
@@ -47,16 +41,9 @@ export default class BattleNetConnection extends Connection {
settings: BattleNetSettings = new BattleNetSettings();
init(): void {
this.settings = ConnectionLoader.getConnectionConfig<BattleNetSettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<BattleNetSettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -75,10 +62,7 @@ export default class BattleNetConnection extends Connection {
return this.tokenUrl;
}
async exchangeCode(
state: string,
code: string,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
async exchangeCode(state: string, code: string): Promise<ConnectedAccountCommonOAuthTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl();
@@ -118,9 +102,7 @@ export default class BattleNetConnection extends Connection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");
+6 -24
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
Connection,
ConnectionLoader,
DiscordApiErrors,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
import { DiscordSettings } from "./DiscordSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
interface UserResponse {
id: string;
@@ -43,16 +37,9 @@ export default class DiscordConnection extends Connection {
settings: DiscordSettings = new DiscordSettings();
init(): void {
this.settings = ConnectionLoader.getConnectionConfig<DiscordSettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<DiscordSettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -74,10 +61,7 @@ export default class DiscordConnection extends Connection {
return this.tokenUrl;
}
async exchangeCode(
state: string,
code: string,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
async exchangeCode(state: string, code: string): Promise<ConnectedAccountCommonOAuthTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl();
@@ -117,9 +101,7 @@ export default class DiscordConnection extends Connection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");
+10 -34
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
Connection,
ConnectionLoader,
DiscordApiErrors,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
import { EpicGamesSettings } from "./EpicGamesSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
export interface UserResponse {
accountId: string;
@@ -33,8 +27,7 @@ export interface UserResponse {
preferredLanguage: string;
}
export interface EpicTokenResponse
extends ConnectedAccountCommonOAuthTokenResponse {
export interface EpicTokenResponse extends ConnectedAccountCommonOAuthTokenResponse {
expires_at: string;
refresh_expires_in: number;
refresh_expires_at: string;
@@ -47,22 +40,14 @@ export default class EpicGamesConnection extends Connection {
public readonly id = "epicgames";
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";
public readonly userInfoUrl = "https://api.epicgames.dev/epic/id/v1/accounts";
public readonly scopes = ["basic profile"];
settings: EpicGamesSettings = new EpicGamesSettings();
init(): void {
this.settings = ConnectionLoader.getConnectionConfig<EpicGamesSettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<EpicGamesSettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -81,10 +66,7 @@ export default class EpicGamesConnection extends Connection {
return this.tokenUrl;
}
async exchangeCode(
state: string,
code: string,
): Promise<EpicTokenResponse> {
async exchangeCode(state: string, code: string): Promise<EpicTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl();
@@ -92,9 +74,7 @@ export default class EpicGamesConnection extends Connection {
return wretch(url.toString())
.headers({
Accept: "application/json",
Authorization: `Basic ${Buffer.from(
`${this.settings.clientId}:${this.settings.clientSecret}`,
).toString("base64")}`,
Authorization: `Basic ${Buffer.from(`${this.settings.clientId}:${this.settings.clientSecret}`).toString("base64")}`,
"Content-Type": "application/x-www-form-urlencoded",
})
.body(
@@ -112,9 +92,7 @@ export default class EpicGamesConnection extends Connection {
}
async getUser(token: string): Promise<UserResponse[]> {
const { sub } = JSON.parse(
Buffer.from(token.split(".")[1], "base64").toString("utf8"),
);
const { sub } = JSON.parse(Buffer.from(token.split(".")[1], "base64").toString("utf8"));
const url = new URL(this.userInfoUrl);
url.searchParams.append("accountId", sub);
@@ -130,9 +108,7 @@ export default class EpicGamesConnection extends Connection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");
+9 -32
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
Connection,
ConnectionLoader,
DiscordApiErrors,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
import { FacebookSettings } from "./FacebookSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
export interface FacebookErrorResponse {
error: {
@@ -43,25 +37,16 @@ interface UserResponse {
export default class FacebookConnection extends Connection {
public readonly id = "facebook";
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 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";
public readonly scopes = ["public_profile"];
settings: FacebookSettings = new FacebookSettings();
init(): void {
this.settings = ConnectionLoader.getConnectionConfig<FacebookSettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<FacebookSettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -80,19 +65,13 @@ export default class FacebookConnection extends Connection {
getTokenUrl(code: string): string {
const url = new URL(this.tokenUrl);
url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append(
"client_secret",
this.settings.clientSecret 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();
}
async exchangeCode(
state: string,
code: string,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
async exchangeCode(state: string, code: string): Promise<ConnectedAccountCommonOAuthTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl(code);
@@ -124,9 +103,7 @@ export default class FacebookConnection extends Connection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");
+7 -28
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
Connection,
ConnectionLoader,
DiscordApiErrors,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
import { GitHubSettings } from "./GitHubSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
interface UserResponse {
login: string;
@@ -42,16 +36,9 @@ export default class GitHubConnection extends Connection {
settings: GitHubSettings = new GitHubSettings();
init(): void {
this.settings = ConnectionLoader.getConnectionConfig<GitHubSettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<GitHubSettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -68,18 +55,12 @@ export default class GitHubConnection extends Connection {
getTokenUrl(code: string): string {
const url = new URL(this.tokenUrl);
url.searchParams.append("client_id", this.settings.clientId as string);
url.searchParams.append(
"client_secret",
this.settings.clientSecret as string,
);
url.searchParams.append("client_secret", this.settings.clientSecret as string);
url.searchParams.append("code", code);
return url.toString();
}
async exchangeCode(
state: string,
code: string,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
async exchangeCode(state: string, code: string): Promise<ConnectedAccountCommonOAuthTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl(code);
@@ -111,9 +92,7 @@ export default class GitHubConnection extends Connection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");
+7 -27
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
Connection,
ConnectionLoader,
DiscordApiErrors,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
import { RedditSettings } from "./RedditSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
export interface UserResponse {
verified: boolean;
@@ -54,16 +48,9 @@ export default class RedditConnection extends Connection {
settings: RedditSettings = new RedditSettings();
init(): void {
this.settings = ConnectionLoader.getConnectionConfig<RedditSettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<RedditSettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -82,10 +69,7 @@ export default class RedditConnection extends Connection {
return this.tokenUrl;
}
async exchangeCode(
state: string,
code: string,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
async exchangeCode(state: string, code: string): Promise<ConnectedAccountCommonOAuthTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl();
@@ -93,9 +77,7 @@ export default class RedditConnection extends Connection {
return wretch(url.toString())
.headers({
Accept: "application/json",
Authorization: `Basic ${Buffer.from(
`${this.settings.clientId}:${this.settings.clientSecret}`,
).toString("base64")}`,
Authorization: `Basic ${Buffer.from(`${this.settings.clientId}:${this.settings.clientSecret}`).toString("base64")}`,
"Content-Type": "application/x-www-form-urlencoded",
})
.body(
@@ -127,9 +109,7 @@ export default class RedditConnection extends Connection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");
+11 -45
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
ConnectionLoader,
DiscordApiErrors,
RefreshableConnection,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionLoader, DiscordApiErrors, RefreshableConnection } from "@spacebar/util";
import wretch from "wretch";
import { SpotifySettings } from "./SpotifySettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
export interface UserResponse {
display_name: string;
@@ -49,12 +43,7 @@ export default class SpotifyConnection extends RefreshableConnection {
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";
public readonly scopes = [
"user-read-private",
"user-read-playback-state",
"user-modify-playback-state",
"user-read-currently-playing",
];
public readonly scopes = ["user-read-private", "user-read-playback-state", "user-modify-playback-state", "user-read-currently-playing"];
settings: SpotifySettings = new SpotifySettings();
init(): void {
@@ -64,16 +53,9 @@ export default class SpotifyConnection extends RefreshableConnection {
*/
this.refreshEnabled = false;
this.settings = ConnectionLoader.getConnectionConfig<SpotifySettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<SpotifySettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -92,10 +74,7 @@ export default class SpotifyConnection extends RefreshableConnection {
return this.tokenUrl;
}
async exchangeCode(
state: string,
code: string,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
async exchangeCode(state: string, code: string): Promise<ConnectedAccountCommonOAuthTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl();
@@ -104,11 +83,7 @@ export default class SpotifyConnection extends RefreshableConnection {
.headers({
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
`${this.settings.clientId as string}:${
this.settings.clientSecret as string
}`,
).toString("base64")}`,
Authorization: `Basic ${Buffer.from(`${this.settings.clientId as string}:${this.settings.clientSecret as string}`).toString("base64")}`,
})
.body(
new URLSearchParams({
@@ -125,11 +100,8 @@ export default class SpotifyConnection extends RefreshableConnection {
});
}
async refreshToken(
connectedAccount: ConnectedAccount,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
if (!connectedAccount.token_data?.refresh_token)
throw new Error("No refresh token available.");
async refreshToken(connectedAccount: ConnectedAccount): Promise<ConnectedAccountCommonOAuthTokenResponse> {
if (!connectedAccount.token_data?.refresh_token) throw new Error("No refresh token available.");
const refresh_token = connectedAccount.token_data.refresh_token;
const url = this.getTokenUrl();
@@ -137,11 +109,7 @@ export default class SpotifyConnection extends RefreshableConnection {
.headers({
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
`${this.settings.clientId as string}:${
this.settings.clientSecret as string
}`,
).toString("base64")}`,
Authorization: `Basic ${Buffer.from(`${this.settings.clientId as string}:${this.settings.clientSecret as string}`).toString("base64")}`,
})
.body(
new URLSearchParams({
@@ -177,9 +145,7 @@ export default class SpotifyConnection extends RefreshableConnection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");
+9 -34
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
ConnectionLoader,
DiscordApiErrors,
RefreshableConnection,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionLoader, DiscordApiErrors, RefreshableConnection } from "@spacebar/util";
import wretch from "wretch";
import { TwitchSettings } from "./TwitchSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
interface TwitchConnectionUserResponse {
data: {
@@ -47,24 +41,13 @@ export default class TwitchConnection extends RefreshableConnection {
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";
public readonly scopes = [
"channel_subscriptions",
"channel_check_subscription",
"channel:read:subscriptions",
];
public readonly scopes = ["channel_subscriptions", "channel_check_subscription", "channel:read:subscriptions"];
settings: TwitchSettings = new TwitchSettings();
init(): void {
this.settings = ConnectionLoader.getConnectionConfig<TwitchSettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<TwitchSettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -83,10 +66,7 @@ export default class TwitchConnection extends RefreshableConnection {
return this.tokenUrl;
}
async exchangeCode(
state: string,
code: string,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
async exchangeCode(state: string, code: string): Promise<ConnectedAccountCommonOAuthTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl();
@@ -113,11 +93,8 @@ export default class TwitchConnection extends RefreshableConnection {
});
}
async refreshToken(
connectedAccount: ConnectedAccount,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
if (!connectedAccount.token_data?.refresh_token)
throw new Error("No refresh token available.");
async refreshToken(connectedAccount: ConnectedAccount): Promise<ConnectedAccountCommonOAuthTokenResponse> {
if (!connectedAccount.token_data?.refresh_token) throw new Error("No refresh token available.");
const refresh_token = connectedAccount.token_data.refresh_token;
const url = this.getTokenUrl();
@@ -164,9 +141,7 @@ export default class TwitchConnection extends RefreshableConnection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");
+11 -41
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
ConnectionLoader,
DiscordApiErrors,
RefreshableConnection,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, ConnectionLoader, DiscordApiErrors, RefreshableConnection } from "@spacebar/util";
import wretch from "wretch";
import { TwitterSettings } from "./TwitterSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
interface TwitterUserResponse {
data: {
@@ -49,22 +43,14 @@ export default class TwitterConnection extends RefreshableConnection {
public readonly id = "twitter";
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";
public readonly userInfoUrl = "https://api.twitter.com/2/users/me?user.fields=created_at%2Cdescription%2Cid%2Cname%2Cusername%2Cverified%2Clocation%2Curl";
public readonly scopes = ["users.read", "tweet.read"];
settings: TwitterSettings = new TwitterSettings();
init(): void {
this.settings = ConnectionLoader.getConnectionConfig<TwitterSettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<TwitterSettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -85,10 +71,7 @@ export default class TwitterConnection extends RefreshableConnection {
return this.tokenUrl;
}
async exchangeCode(
state: string,
code: string,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
async exchangeCode(state: string, code: string): Promise<ConnectedAccountCommonOAuthTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl();
@@ -97,11 +80,7 @@ export default class TwitterConnection extends RefreshableConnection {
.headers({
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
`${this.settings.clientId as string}:${
this.settings.clientSecret as string
}`,
).toString("base64")}`,
Authorization: `Basic ${Buffer.from(`${this.settings.clientId as string}:${this.settings.clientSecret as string}`).toString("base64")}`,
})
.body(
new URLSearchParams({
@@ -120,11 +99,8 @@ export default class TwitterConnection extends RefreshableConnection {
});
}
async refreshToken(
connectedAccount: ConnectedAccount,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
if (!connectedAccount.token_data?.refresh_token)
throw new Error("No refresh token available.");
async refreshToken(connectedAccount: ConnectedAccount): Promise<ConnectedAccountCommonOAuthTokenResponse> {
if (!connectedAccount.token_data?.refresh_token) throw new Error("No refresh token available.");
const refresh_token = connectedAccount.token_data.refresh_token;
const url = this.getTokenUrl();
@@ -133,11 +109,7 @@ export default class TwitterConnection extends RefreshableConnection {
.headers({
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
`${this.settings.clientId as string}:${
this.settings.clientSecret as string
}`,
).toString("base64")}`,
Authorization: `Basic ${Buffer.from(`${this.settings.clientId as string}:${this.settings.clientSecret as string}`).toString("base64")}`,
})
.body(
new URLSearchParams({
@@ -170,9 +142,7 @@ export default class TwitterConnection extends RefreshableConnection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");
+11 -39
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
Connection,
ConnectionLoader,
DiscordApiErrors,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
import { XboxSettings } from "./XboxSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
interface XboxUserResponse {
IssueInstant: string;
@@ -51,27 +45,17 @@ interface XboxUserResponse {
export default class XboxConnection extends Connection {
public readonly id = "xbox";
public readonly authorizeUrl =
"https://login.live.com/oauth20_authorize.srf";
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";
public readonly userAuthUrl =
"https://user.auth.xboxlive.com/user/authenticate";
public readonly userInfoUrl = "https://xsts.auth.xboxlive.com/xsts/authorize";
public readonly userAuthUrl = "https://user.auth.xboxlive.com/user/authenticate";
public readonly scopes = ["Xboxlive.signin", "Xboxlive.offline_access"];
settings: XboxSettings = new XboxSettings();
init(): void {
this.settings = ConnectionLoader.getConnectionConfig<XboxSettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<XboxSettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -117,10 +101,7 @@ export default class XboxConnection extends Connection {
});
}
async exchangeCode(
state: string,
code: string,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
async exchangeCode(state: string, code: string): Promise<ConnectedAccountCommonOAuthTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl();
@@ -129,11 +110,7 @@ export default class XboxConnection extends Connection {
.headers({
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
`${this.settings.clientId as string}:${
this.settings.clientSecret as string
}`,
).toString("base64")}`,
Authorization: `Basic ${Buffer.from(`${this.settings.clientId as string}:${this.settings.clientSecret as string}`).toString("base64")}`,
})
.body(
new URLSearchParams({
@@ -179,9 +156,7 @@ export default class XboxConnection extends Connection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");
@@ -190,10 +165,7 @@ export default class XboxConnection extends Connection {
const userToken = await this.getUserToken(tokenData.access_token);
const userInfo = await this.getUser(userToken);
const exists = await this.hasConnection(
userId,
userInfo.DisplayClaims.xui[0].xid,
);
const exists = await this.hasConnection(userId, userInfo.DisplayClaims.xui[0].xid);
if (exists) return null;
+9 -31
View File
@@ -16,16 +16,10 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
ConnectedAccount,
ConnectedAccountCommonOAuthTokenResponse,
Connection,
ConnectionLoader,
DiscordApiErrors,
} from "@spacebar/util";
import { ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
import { YoutubeSettings } from "./YoutubeSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas"
import { ConnectionCallbackSchema } from "@spacebar/schemas";
interface YouTubeConnectionChannelListResult {
items: {
@@ -51,27 +45,16 @@ interface YouTubeConnectionChannelListResult {
export default class YoutubeConnection extends Connection {
public readonly id = "youtube";
public readonly authorizeUrl =
"https://accounts.google.com/o/oauth2/v2/auth";
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";
public readonly scopes = [
"https://www.googleapis.com/auth/youtube.readonly",
];
public readonly userInfoUrl = "https://www.googleapis.com/youtube/v3/channels?mine=true&part=snippet";
public readonly scopes = ["https://www.googleapis.com/auth/youtube.readonly"];
settings: YoutubeSettings = new YoutubeSettings();
init(): void {
this.settings = ConnectionLoader.getConnectionConfig<YoutubeSettings>(
this.id,
this.settings,
);
this.settings = ConnectionLoader.getConnectionConfig<YoutubeSettings>(this.id, this.settings);
if (
this.settings.enabled &&
(!this.settings.clientId || !this.settings.clientSecret)
)
throw new Error(`Invalid settings for connection ${this.id}`);
if (this.settings.enabled && (!this.settings.clientId || !this.settings.clientSecret)) throw new Error(`Invalid settings for connection ${this.id}`);
}
getAuthorizationUrl(userId: string): string {
@@ -90,10 +73,7 @@ export default class YoutubeConnection extends Connection {
return this.tokenUrl;
}
async exchangeCode(
state: string,
code: string,
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
async exchangeCode(state: string, code: string): Promise<ConnectedAccountCommonOAuthTokenResponse> {
this.validateState(state);
const url = this.getTokenUrl();
@@ -134,9 +114,7 @@ export default class YoutubeConnection extends Connection {
});
}
async handleCallback(
params: ConnectionCallbackSchema,
): Promise<ConnectedAccount | null> {
async handleCallback(params: ConnectionCallbackSchema): Promise<ConnectedAccount | null> {
const { state, code } = params;
if (!code) throw new Error("No code provided");