diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/connections/BattleNet/index.ts | 73 | ||||
-rw-r--r-- | src/connections/Discord/index.ts | 62 | ||||
-rw-r--r-- | src/connections/EpicGames/index.ts | 52 | ||||
-rw-r--r-- | src/connections/Facebook/index.ts | 55 | ||||
-rw-r--r-- | src/connections/GitHub/index.ts | 42 | ||||
-rw-r--r-- | src/connections/Reddit/index.ts | 58 | ||||
-rw-r--r-- | src/connections/Spotify/index.ts | 123 | ||||
-rw-r--r-- | src/connections/Twitch/index.ts | 107 | ||||
-rw-r--r-- | src/connections/Twitter/index.ts | 120 | ||||
-rw-r--r-- | src/connections/Xbox/index.ts | 134 |
10 files changed, 277 insertions, 549 deletions
diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index 8e8eeeed..96c3993c 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { BattleNetSettings } from "./BattleNetSettings"; @@ -67,68 +66,40 @@ export default class BattleNetConnection extends Connection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - client_id: this.settings.clientId!, - client_secret: this.settings.clientSecret!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - BattleNetErrorResponse, - ) => { - if (res.error) throw new Error(res.error_description); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), ) + .post() + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error exchanging token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise<BattleNetConnectionUser> { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); - }) - .then((res: BattleNetConnectionUser & BattleNetErrorResponse) => { - if (res.error) throw new Error(res.error_description); - return res; }) + .get() + .json<BattleNetConnectionUser>() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 23f5d978..52fc9ffd 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { DiscordSettings } from "./DiscordSettings"; @@ -66,56 +65,41 @@ export default class DiscordConnection extends Connection { this.validateState(state); const url = this.getTokenUrl(); - return fetch(url, { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - client_id: this.settings.clientId!, - client_secret: this.settings.clientSecret!, - grant_type: "authorization_code", - code: code, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange token", 0, 400); - } - - return res.json(); }) + .body( + new URLSearchParams({ + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + grant_type: "authorization_code", + code: code, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + ) + .post() + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error exchanging token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise<UserResponse> { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); }) + .get() + .json<UserResponse>() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts index c720dc5d..247d2435 100644 --- a/src/connections/EpicGames/index.ts +++ b/src/connections/EpicGames/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { EpicGamesSettings } from "./EpicGamesSettings"; @@ -73,31 +72,24 @@ export default class EpicGamesConnection extends Connection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", Authorization: `Basic ${Buffer.from( `${this.settings.clientId}:${this.settings.clientSecret}`, ).toString("base64")}`, "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code, + }), + ) + .post() + .json<EpicTokenResponse>() .catch((e) => { - console.error( - `Error exchanging token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -108,23 +100,15 @@ export default class EpicGamesConnection extends Connection { ); const url = new URL(this.userInfoUrl); url.searchParams.append("accountId", sub); - return fetch(url.toString(), { - method: "GET", - headers: { + + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); }) + .get() + .json<UserResponse[]>() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts index 67f8da79..5413f867 100644 --- a/src/connections/Facebook/index.ts +++ b/src/connections/Facebook/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { FacebookSettings } from "./FacebookSettings"; @@ -83,59 +82,29 @@ export default class FacebookConnection extends Connection { const url = this.getTokenUrl(code); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - FacebookErrorResponse, - ) => { - if (res.error) throw new Error(res.error.message); - return res; - }, - ) + .get() + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error exchanging token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise<UserResponse> { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); - }) - .then((res: UserResponse & FacebookErrorResponse) => { - if (res.error) throw new Error(res.error.message); - return res; }) + .get() + .json<UserResponse>() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index aa686b03..8380e765 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { GitHubSettings } from "./GitHubSettings"; @@ -65,46 +64,29 @@ export default class GitHubConnection extends Connection { const url = this.getTokenUrl(code); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) + + .post() + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise<UserResponse> { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); }) + .get() + .json<UserResponse>() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts index 06fbcbe5..70b4a8af 100644 --- a/src/connections/Reddit/index.ts +++ b/src/connections/Reddit/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { RedditSettings } from "./RedditSettings"; @@ -74,57 +73,42 @@ export default class RedditConnection extends Connection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", Authorization: `Basic ${Buffer.from( `${this.settings.clientId}:${this.settings.clientSecret}`, ).toString("base64")}`, "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to code", 0, 400); - } - - return res.json(); }) + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + ) + .post() + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise<UserResponse> { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); }) + .get() + .json<UserResponse>() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts index 44a4bc28..54ec2696 100644 --- a/src/connections/Spotify/index.ts +++ b/src/connections/Spotify/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import RefreshableConnection from "../../util/connections/RefreshableConnection"; import { SpotifySettings } from "./SpotifySettings"; @@ -83,122 +82,78 @@ export default class SpotifyConnection extends RefreshableConnection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from( `${this.settings.clientId!}:${this.settings.clientSecret!}`, ).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to refresh token", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - TokenErrorResponse, - ) => { - if (res.error) - throw new ApiError(res.error_description, 0, 400); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), ) + .post() + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } - async refreshToken(connectedAccount: ConnectedAccount) { + 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(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from( `${this.settings.clientId!}:${this.settings.clientSecret!}`, ).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "refresh_token", - refresh_token, - }), - }) - .then(async (res) => { - if ([400, 401].includes(res.status)) { - // assume the token was revoked - await connectedAccount.revoke(); - return DiscordApiErrors.CONNECTION_REVOKED; - } - // otherwise throw a general error - if (!res.ok) { - throw new ApiError("Failed to refresh token", 0, 400); - } - - return await res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - TokenErrorResponse, - ) => { - if (res.error) - throw new ApiError(res.error_description, 0, 400); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "refresh_token", + refresh_token, + }), ) + .post() + .unauthorized(async () => { + // assume the token was revoked + await connectedAccount.revoke(); + return DiscordApiErrors.CONNECTION_REVOKED; + }) + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error refreshing token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise<UserResponse> { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); - }) - .then((res: UserResponse & ErrorResponse) => { - if (res.error) throw new Error(res.error.message); - return res; }) + .get() + .json<UserResponse>() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Twitch/index.ts b/src/connections/Twitch/index.ts index ce04f098..264db3cc 100644 --- a/src/connections/Twitch/index.ts +++ b/src/connections/Twitch/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import RefreshableConnection from "../../util/connections/RefreshableConnection"; import { TwitchSettings } from "./TwitchSettings"; @@ -75,33 +74,27 @@ export default class TwitchConnection extends RefreshableConnection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - client_id: this.settings.clientId!, - client_secret: this.settings.clientSecret!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + ) + .post() + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -115,60 +108,44 @@ export default class TwitchConnection extends RefreshableConnection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - grant_type: "refresh_token", - client_id: this.settings.clientId!, - client_secret: this.settings.clientSecret!, - refresh_token: refresh_token, - }), - }) - .then(async (res) => { - if ([400, 401].includes(res.status)) { - // assume the token was revoked - await connectedAccount.revoke(); - return DiscordApiErrors.CONNECTION_REVOKED; - } - // otherwise throw a general error - if (!res.ok) { - throw new ApiError("Failed to refresh token", 0, 400); - } - - return await res.json(); }) + .body( + new URLSearchParams({ + grant_type: "refresh_token", + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + refresh_token: refresh_token, + }), + ) + .post() + .unauthorized(async () => { + // assume the token was revoked + await connectedAccount.revoke(); + return DiscordApiErrors.CONNECTION_REVOKED; + }) + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error refreshing token for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise<TwitchConnectionUserResponse> { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, "Client-Id": this.settings.clientId!, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); }) + .get() + .json<TwitchConnectionUserResponse>() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Twitter/index.ts b/src/connections/Twitter/index.ts index d8a765ac..ad9d55d4 100644 --- a/src/connections/Twitter/index.ts +++ b/src/connections/Twitter/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import RefreshableConnection from "../../util/connections/RefreshableConnection"; import { TwitterSettings } from "./TwitterSettings"; @@ -77,45 +76,30 @@ export default class TwitterConnection extends RefreshableConnection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from( `${this.settings.clientId!}:${this.settings.clientSecret!}`, ).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - client_id: this.settings.clientId!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - code_verifier: "challenge", // TODO: properly use PKCE challenge - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - TwitterErrorResponse, - ) => { - if (res.error) throw new Error(res.error_description); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + code_verifier: "challenge", // TODO: properly use PKCE challenge + }), ) + .post() + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -129,72 +113,44 @@ export default class TwitterConnection extends RefreshableConnection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from( `${this.settings.clientId!}:${this.settings.clientSecret!}`, ).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "refresh_token", - refresh_token, - client_id: this.settings.clientId!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - code_verifier: "challenge", // TODO: properly use PKCE challenge - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - TwitterErrorResponse, - ) => { - if (res.error) throw new Error(res.error_description); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "refresh_token", + refresh_token, + client_id: this.settings.clientId!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + code_verifier: "challenge", // TODO: properly use PKCE challenge + }), ) + .post() + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise<TwitterUserResponse> { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "GET", - headers: { + return wretch(url.toString()) + .headers({ Authorization: `Bearer ${token}`, - }, - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); - }) - .then((res: TwitterUserResponse & TwitterErrorResponse) => { - if (res.error) throw new Error(res.error_description); - return res; }) + .get() + .json<TwitterUserResponse>() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Xbox/index.ts b/src/connections/Xbox/index.ts index eb0e2496..80a04dea 100644 --- a/src/connections/Xbox/index.ts +++ b/src/connections/Xbox/index.ts @@ -1,5 +1,4 @@ import { - ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -7,7 +6,7 @@ import { ConnectionLoader, DiscordApiErrors, } from "@fosscord/util"; -import fetch from "node-fetch"; +import wretch from "wretch"; import Connection from "../../util/connections/Connection"; import { XboxSettings } from "./XboxSettings"; @@ -76,36 +75,28 @@ export default class XboxConnection extends Connection { } async getUserToken(token: string): Promise<string> { - return fetch(this.userAuthUrl, { - method: "POST", - headers: { + return wretch(this.userAuthUrl) + .headers({ "x-xbl-contract-version": "3", "Content-Type": "application/json", Accept: "application/json", - }, - body: JSON.stringify({ - RelyingParty: "http://auth.xboxlive.com", - TokenType: "JWT", - Properties: { - AuthMethod: "RPS", - SiteName: "user.auth.xboxlive.com", - RpsTicket: `d=${token}`, - }, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to get user token", 0, 400); - } - - return res.json(); }) - .then((res) => res.Token) + .body( + JSON.stringify({ + RelyingParty: "http://auth.xboxlive.com", + TokenType: "JWT", + Properties: { + AuthMethod: "RPS", + SiteName: "user.auth.xboxlive.com", + RpsTicket: `d=${token}`, + }, + }), + ) + .post() + .json((res: XboxUserResponse) => res.Token) .catch((e) => { - console.error( - `Error getting user token for ${this.id} connection: ${e}`, - ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + console.error(e); + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -117,82 +108,57 @@ export default class XboxConnection extends Connection { const url = this.getTokenUrl(); - return fetch(url.toString(), { - method: "POST", - headers: { + return wretch(url.toString()) + .headers({ Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from( `${this.settings.clientId!}:${this.settings.clientSecret!}`, ).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "authorization_code", - code: code, - client_id: this.settings.clientId!, - redirect_uri: `${ - Config.get().cdn.endpointPrivate || "http://localhost:3001" - }/connections/${this.id}/callback`, - scope: this.scopes.join(" "), - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to exchange code", 0, 400); - } - - return res.json(); }) - .then( - ( - res: ConnectedAccountCommonOAuthTokenResponse & - XboxErrorResponse, - ) => { - if (res.error) throw new Error(res.error_description); - return res; - }, + .body( + new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || + "http://localhost:3001" + }/connections/${this.id}/callback`, + scope: this.scopes.join(" "), + }), ) + .post() + .json<ConnectedAccountCommonOAuthTokenResponse>() .catch((e) => { - console.error( - `Error exchanging code for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } async getUser(token: string): Promise<XboxUserResponse> { const url = new URL(this.userInfoUrl); - return fetch(url.toString(), { - method: "POST", - headers: { + + return wretch(url.toString()) + .headers({ "x-xbl-contract-version": "3", "Content-Type": "application/json", Accept: "application/json", - }, - body: JSON.stringify({ - RelyingParty: "http://xboxlive.com", - TokenType: "JWT", - Properties: { - UserTokens: [token], - SandboxId: "RETAIL", - }, - }), - }) - .then((res) => { - if (!res.ok) { - throw new ApiError("Failed to fetch user", 0, 400); - } - - return res.json(); - }) - .then((res: XboxUserResponse & XboxErrorResponse) => { - if (res.error) throw new Error(res.error_description); - return res; }) + .body( + JSON.stringify({ + RelyingParty: "http://xboxlive.com", + TokenType: "JWT", + Properties: { + UserTokens: [token], + SandboxId: "RETAIL", + }, + }), + ) + .post() + .json<XboxUserResponse>() .catch((e) => { - console.error( - `Error fetching user for ${this.id} connection: ${e}`, - ); + console.error(e); throw DiscordApiErrors.GENERAL_ERROR; }); } |