replace node-fetch with wretch
This commit is contained in:
parent
06140fc768
commit
d8ecc4269f
9
package-lock.json
generated
9
package-lock.json
generated
@ -50,6 +50,7 @@
|
|||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typeorm": "^0.3.10",
|
"typeorm": "^0.3.10",
|
||||||
"typescript-json-schema": "^0.50.1",
|
"typescript-json-schema": "^0.50.1",
|
||||||
|
"wretch": "^2.3.2",
|
||||||
"ws": "^8.9.0"
|
"ws": "^8.9.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -7988,6 +7989,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/wretch": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wretch/-/wretch-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-brN97Z2Mwed+w5z+keYI1u5OwWhPIaW0sJi9CxtKBVxLc3aqP6j1+2FCoIskM7WJq6SUHdxTFx20ox0iDLa0mQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.11.0",
|
"version": "8.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
||||||
|
@ -105,6 +105,7 @@
|
|||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typeorm": "^0.3.10",
|
"typeorm": "^0.3.10",
|
||||||
"typescript-json-schema": "^0.50.1",
|
"typescript-json-schema": "^0.50.1",
|
||||||
|
"wretch": "^2.3.2",
|
||||||
"ws": "^8.9.0"
|
"ws": "^8.9.0"
|
||||||
},
|
},
|
||||||
"_moduleAliases": {
|
"_moduleAliases": {
|
||||||
|
5745
pnpm-lock.yaml
generated
Normal file
5745
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ApiError,
|
|
||||||
Config,
|
Config,
|
||||||
ConnectedAccount,
|
ConnectedAccount,
|
||||||
ConnectedAccountCommonOAuthTokenResponse,
|
ConnectedAccountCommonOAuthTokenResponse,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
ConnectionLoader,
|
ConnectionLoader,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
} from "@fosscord/util";
|
} from "@fosscord/util";
|
||||||
import fetch from "node-fetch";
|
import wretch from "wretch";
|
||||||
import Connection from "../../util/connections/Connection";
|
import Connection from "../../util/connections/Connection";
|
||||||
import { BattleNetSettings } from "./BattleNetSettings";
|
import { BattleNetSettings } from "./BattleNetSettings";
|
||||||
|
|
||||||
@ -67,68 +66,40 @@ export default class BattleNetConnection extends Connection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
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(
|
.body(
|
||||||
(
|
new URLSearchParams({
|
||||||
res: ConnectedAccountCommonOAuthTokenResponse &
|
grant_type: "authorization_code",
|
||||||
BattleNetErrorResponse,
|
code: code,
|
||||||
) => {
|
client_id: this.settings.clientId!,
|
||||||
if (res.error) throw new Error(res.error_description);
|
client_secret: this.settings.clientSecret!,
|
||||||
return res;
|
redirect_uri: `${
|
||||||
},
|
Config.get().cdn.endpointPrivate ||
|
||||||
|
"http://localhost:3001"
|
||||||
|
}/connections/${this.id}/callback`,
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
.post()
|
||||||
|
.json<ConnectedAccountCommonOAuthTokenResponse>()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging token for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUser(token: string): Promise<BattleNetConnectionUser> {
|
async getUser(token: string): Promise<BattleNetConnectionUser> {
|
||||||
const url = new URL(this.userInfoUrl);
|
const url = new URL(this.userInfoUrl);
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "GET",
|
.headers({
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error fetching user for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ApiError,
|
|
||||||
Config,
|
Config,
|
||||||
ConnectedAccount,
|
ConnectedAccount,
|
||||||
ConnectedAccountCommonOAuthTokenResponse,
|
ConnectedAccountCommonOAuthTokenResponse,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
ConnectionLoader,
|
ConnectionLoader,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
} from "@fosscord/util";
|
} from "@fosscord/util";
|
||||||
import fetch from "node-fetch";
|
import wretch from "wretch";
|
||||||
import Connection from "../../util/connections/Connection";
|
import Connection from "../../util/connections/Connection";
|
||||||
import { DiscordSettings } from "./DiscordSettings";
|
import { DiscordSettings } from "./DiscordSettings";
|
||||||
|
|
||||||
@ -66,56 +65,41 @@ export default class DiscordConnection extends Connection {
|
|||||||
this.validateState(state);
|
this.validateState(state);
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url, {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging token for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUser(token: string): Promise<UserResponse> {
|
async getUser(token: string): Promise<UserResponse> {
|
||||||
const url = new URL(this.userInfoUrl);
|
const url = new URL(this.userInfoUrl);
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "GET",
|
.headers({
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error fetching user for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ApiError,
|
|
||||||
Config,
|
Config,
|
||||||
ConnectedAccount,
|
ConnectedAccount,
|
||||||
ConnectedAccountCommonOAuthTokenResponse,
|
ConnectedAccountCommonOAuthTokenResponse,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
ConnectionLoader,
|
ConnectionLoader,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
} from "@fosscord/util";
|
} from "@fosscord/util";
|
||||||
import fetch from "node-fetch";
|
import wretch from "wretch";
|
||||||
import Connection from "../../util/connections/Connection";
|
import Connection from "../../util/connections/Connection";
|
||||||
import { EpicGamesSettings } from "./EpicGamesSettings";
|
import { EpicGamesSettings } from "./EpicGamesSettings";
|
||||||
|
|
||||||
@ -73,31 +72,24 @@ export default class EpicGamesConnection extends Connection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
Authorization: `Basic ${Buffer.from(
|
Authorization: `Basic ${Buffer.from(
|
||||||
`${this.settings.clientId}:${this.settings.clientSecret}`,
|
`${this.settings.clientId}:${this.settings.clientSecret}`,
|
||||||
).toString("base64")}`,
|
).toString("base64")}`,
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging token for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -108,23 +100,15 @@ export default class EpicGamesConnection extends Connection {
|
|||||||
);
|
);
|
||||||
const url = new URL(this.userInfoUrl);
|
const url = new URL(this.userInfoUrl);
|
||||||
url.searchParams.append("accountId", sub);
|
url.searchParams.append("accountId", sub);
|
||||||
return fetch(url.toString(), {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new ApiError("Failed to fetch user", 0, 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json();
|
return wretch(url.toString())
|
||||||
|
.headers({
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
})
|
})
|
||||||
|
.get()
|
||||||
|
.json<UserResponse[]>()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error fetching user for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ApiError,
|
|
||||||
Config,
|
Config,
|
||||||
ConnectedAccount,
|
ConnectedAccount,
|
||||||
ConnectedAccountCommonOAuthTokenResponse,
|
ConnectedAccountCommonOAuthTokenResponse,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
ConnectionLoader,
|
ConnectionLoader,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
} from "@fosscord/util";
|
} from "@fosscord/util";
|
||||||
import fetch from "node-fetch";
|
import wretch from "wretch";
|
||||||
import Connection from "../../util/connections/Connection";
|
import Connection from "../../util/connections/Connection";
|
||||||
import { FacebookSettings } from "./FacebookSettings";
|
import { FacebookSettings } from "./FacebookSettings";
|
||||||
|
|
||||||
@ -83,59 +82,29 @@ export default class FacebookConnection extends Connection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl(code);
|
const url = this.getTokenUrl(code);
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "GET",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
},
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new ApiError("Failed to exchange code", 0, 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json();
|
|
||||||
})
|
})
|
||||||
.then(
|
.get()
|
||||||
(
|
.json<ConnectedAccountCommonOAuthTokenResponse>()
|
||||||
res: ConnectedAccountCommonOAuthTokenResponse &
|
|
||||||
FacebookErrorResponse,
|
|
||||||
) => {
|
|
||||||
if (res.error) throw new Error(res.error.message);
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging token for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUser(token: string): Promise<UserResponse> {
|
async getUser(token: string): Promise<UserResponse> {
|
||||||
const url = new URL(this.userInfoUrl);
|
const url = new URL(this.userInfoUrl);
|
||||||
return fetch(url.toString(), {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new ApiError("Failed to fetch user", 0, 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json();
|
return wretch(url.toString())
|
||||||
})
|
.headers({
|
||||||
.then((res: UserResponse & FacebookErrorResponse) => {
|
Authorization: `Bearer ${token}`,
|
||||||
if (res.error) throw new Error(res.error.message);
|
|
||||||
return res;
|
|
||||||
})
|
})
|
||||||
|
.get()
|
||||||
|
.json<UserResponse>()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error fetching user for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ApiError,
|
|
||||||
Config,
|
Config,
|
||||||
ConnectedAccount,
|
ConnectedAccount,
|
||||||
ConnectedAccountCommonOAuthTokenResponse,
|
ConnectedAccountCommonOAuthTokenResponse,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
ConnectionLoader,
|
ConnectionLoader,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
} from "@fosscord/util";
|
} from "@fosscord/util";
|
||||||
import fetch from "node-fetch";
|
import wretch from "wretch";
|
||||||
import Connection from "../../util/connections/Connection";
|
import Connection from "../../util/connections/Connection";
|
||||||
import { GitHubSettings } from "./GitHubSettings";
|
import { GitHubSettings } from "./GitHubSettings";
|
||||||
|
|
||||||
@ -65,46 +64,29 @@ export default class GitHubConnection extends Connection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl(code);
|
const url = this.getTokenUrl(code);
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging code for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUser(token: string): Promise<UserResponse> {
|
async getUser(token: string): Promise<UserResponse> {
|
||||||
const url = new URL(this.userInfoUrl);
|
const url = new URL(this.userInfoUrl);
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "GET",
|
.headers({
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error fetching user for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ApiError,
|
|
||||||
Config,
|
Config,
|
||||||
ConnectedAccount,
|
ConnectedAccount,
|
||||||
ConnectedAccountCommonOAuthTokenResponse,
|
ConnectedAccountCommonOAuthTokenResponse,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
ConnectionLoader,
|
ConnectionLoader,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
} from "@fosscord/util";
|
} from "@fosscord/util";
|
||||||
import fetch from "node-fetch";
|
import wretch from "wretch";
|
||||||
import Connection from "../../util/connections/Connection";
|
import Connection from "../../util/connections/Connection";
|
||||||
import { RedditSettings } from "./RedditSettings";
|
import { RedditSettings } from "./RedditSettings";
|
||||||
|
|
||||||
@ -74,57 +73,42 @@ export default class RedditConnection extends Connection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
Authorization: `Basic ${Buffer.from(
|
Authorization: `Basic ${Buffer.from(
|
||||||
`${this.settings.clientId}:${this.settings.clientSecret}`,
|
`${this.settings.clientId}:${this.settings.clientSecret}`,
|
||||||
).toString("base64")}`,
|
).toString("base64")}`,
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging code for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUser(token: string): Promise<UserResponse> {
|
async getUser(token: string): Promise<UserResponse> {
|
||||||
const url = new URL(this.userInfoUrl);
|
const url = new URL(this.userInfoUrl);
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "GET",
|
.headers({
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error fetching user for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ApiError,
|
|
||||||
Config,
|
Config,
|
||||||
ConnectedAccount,
|
ConnectedAccount,
|
||||||
ConnectedAccountCommonOAuthTokenResponse,
|
ConnectedAccountCommonOAuthTokenResponse,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
ConnectionLoader,
|
ConnectionLoader,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
} from "@fosscord/util";
|
} from "@fosscord/util";
|
||||||
import fetch from "node-fetch";
|
import wretch from "wretch";
|
||||||
import RefreshableConnection from "../../util/connections/RefreshableConnection";
|
import RefreshableConnection from "../../util/connections/RefreshableConnection";
|
||||||
import { SpotifySettings } from "./SpotifySettings";
|
import { SpotifySettings } from "./SpotifySettings";
|
||||||
|
|
||||||
@ -83,122 +82,78 @@ export default class SpotifyConnection extends RefreshableConnection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
Authorization: `Basic ${Buffer.from(
|
Authorization: `Basic ${Buffer.from(
|
||||||
`${this.settings.clientId!}:${this.settings.clientSecret!}`,
|
`${this.settings.clientId!}:${this.settings.clientSecret!}`,
|
||||||
).toString("base64")}`,
|
).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(
|
.body(
|
||||||
(
|
new URLSearchParams({
|
||||||
res: ConnectedAccountCommonOAuthTokenResponse &
|
grant_type: "authorization_code",
|
||||||
TokenErrorResponse,
|
code: code,
|
||||||
) => {
|
redirect_uri: `${
|
||||||
if (res.error)
|
Config.get().cdn.endpointPrivate ||
|
||||||
throw new ApiError(res.error_description, 0, 400);
|
"http://localhost:3001"
|
||||||
return res;
|
}/connections/${this.id}/callback`,
|
||||||
},
|
}),
|
||||||
)
|
)
|
||||||
|
.post()
|
||||||
|
.json<ConnectedAccountCommonOAuthTokenResponse>()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging code for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshToken(connectedAccount: ConnectedAccount) {
|
async refreshToken(
|
||||||
|
connectedAccount: ConnectedAccount,
|
||||||
|
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
|
||||||
if (!connectedAccount.token_data?.refresh_token)
|
if (!connectedAccount.token_data?.refresh_token)
|
||||||
throw new Error("No refresh token available.");
|
throw new Error("No refresh token available.");
|
||||||
const refresh_token = connectedAccount.token_data.refresh_token;
|
const refresh_token = connectedAccount.token_data.refresh_token;
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
Authorization: `Basic ${Buffer.from(
|
Authorization: `Basic ${Buffer.from(
|
||||||
`${this.settings.clientId!}:${this.settings.clientSecret!}`,
|
`${this.settings.clientId!}:${this.settings.clientSecret!}`,
|
||||||
).toString("base64")}`,
|
).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(
|
.body(
|
||||||
(
|
new URLSearchParams({
|
||||||
res: ConnectedAccountCommonOAuthTokenResponse &
|
grant_type: "refresh_token",
|
||||||
TokenErrorResponse,
|
refresh_token,
|
||||||
) => {
|
}),
|
||||||
if (res.error)
|
|
||||||
throw new ApiError(res.error_description, 0, 400);
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
.post()
|
||||||
|
.unauthorized(async () => {
|
||||||
|
// assume the token was revoked
|
||||||
|
await connectedAccount.revoke();
|
||||||
|
return DiscordApiErrors.CONNECTION_REVOKED;
|
||||||
|
})
|
||||||
|
.json<ConnectedAccountCommonOAuthTokenResponse>()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error refreshing token for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUser(token: string): Promise<UserResponse> {
|
async getUser(token: string): Promise<UserResponse> {
|
||||||
const url = new URL(this.userInfoUrl);
|
const url = new URL(this.userInfoUrl);
|
||||||
return fetch(url.toString(), {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new ApiError("Failed to fetch user", 0, 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json();
|
return wretch(url.toString())
|
||||||
})
|
.headers({
|
||||||
.then((res: UserResponse & ErrorResponse) => {
|
Authorization: `Bearer ${token}`,
|
||||||
if (res.error) throw new Error(res.error.message);
|
|
||||||
return res;
|
|
||||||
})
|
})
|
||||||
|
.get()
|
||||||
|
.json<UserResponse>()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error fetching user for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ApiError,
|
|
||||||
Config,
|
Config,
|
||||||
ConnectedAccount,
|
ConnectedAccount,
|
||||||
ConnectedAccountCommonOAuthTokenResponse,
|
ConnectedAccountCommonOAuthTokenResponse,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
ConnectionLoader,
|
ConnectionLoader,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
} from "@fosscord/util";
|
} from "@fosscord/util";
|
||||||
import fetch from "node-fetch";
|
import wretch from "wretch";
|
||||||
import RefreshableConnection from "../../util/connections/RefreshableConnection";
|
import RefreshableConnection from "../../util/connections/RefreshableConnection";
|
||||||
import { TwitchSettings } from "./TwitchSettings";
|
import { TwitchSettings } from "./TwitchSettings";
|
||||||
|
|
||||||
@ -75,33 +74,27 @@ export default class TwitchConnection extends RefreshableConnection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging code for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -115,60 +108,44 @@ export default class TwitchConnection extends RefreshableConnection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error refreshing token for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUser(token: string): Promise<TwitchConnectionUserResponse> {
|
async getUser(token: string): Promise<TwitchConnectionUserResponse> {
|
||||||
const url = new URL(this.userInfoUrl);
|
const url = new URL(this.userInfoUrl);
|
||||||
return fetch(url.toString(), {
|
|
||||||
method: "GET",
|
return wretch(url.toString())
|
||||||
headers: {
|
.headers({
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
"Client-Id": this.settings.clientId!,
|
"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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error fetching user for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ApiError,
|
|
||||||
Config,
|
Config,
|
||||||
ConnectedAccount,
|
ConnectedAccount,
|
||||||
ConnectedAccountCommonOAuthTokenResponse,
|
ConnectedAccountCommonOAuthTokenResponse,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
ConnectionLoader,
|
ConnectionLoader,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
} from "@fosscord/util";
|
} from "@fosscord/util";
|
||||||
import fetch from "node-fetch";
|
import wretch from "wretch";
|
||||||
import RefreshableConnection from "../../util/connections/RefreshableConnection";
|
import RefreshableConnection from "../../util/connections/RefreshableConnection";
|
||||||
import { TwitterSettings } from "./TwitterSettings";
|
import { TwitterSettings } from "./TwitterSettings";
|
||||||
|
|
||||||
@ -77,45 +76,30 @@ export default class TwitterConnection extends RefreshableConnection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
Authorization: `Basic ${Buffer.from(
|
Authorization: `Basic ${Buffer.from(
|
||||||
`${this.settings.clientId!}:${this.settings.clientSecret!}`,
|
`${this.settings.clientId!}:${this.settings.clientSecret!}`,
|
||||||
).toString("base64")}`,
|
).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(
|
.body(
|
||||||
(
|
new URLSearchParams({
|
||||||
res: ConnectedAccountCommonOAuthTokenResponse &
|
grant_type: "authorization_code",
|
||||||
TwitterErrorResponse,
|
code: code,
|
||||||
) => {
|
client_id: this.settings.clientId!,
|
||||||
if (res.error) throw new Error(res.error_description);
|
redirect_uri: `${
|
||||||
return res;
|
Config.get().cdn.endpointPrivate ||
|
||||||
},
|
"http://localhost:3001"
|
||||||
|
}/connections/${this.id}/callback`,
|
||||||
|
code_verifier: "challenge", // TODO: properly use PKCE challenge
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
.post()
|
||||||
|
.json<ConnectedAccountCommonOAuthTokenResponse>()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging code for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -129,72 +113,44 @@ export default class TwitterConnection extends RefreshableConnection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
Authorization: `Basic ${Buffer.from(
|
Authorization: `Basic ${Buffer.from(
|
||||||
`${this.settings.clientId!}:${this.settings.clientSecret!}`,
|
`${this.settings.clientId!}:${this.settings.clientSecret!}`,
|
||||||
).toString("base64")}`,
|
).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(
|
.body(
|
||||||
(
|
new URLSearchParams({
|
||||||
res: ConnectedAccountCommonOAuthTokenResponse &
|
grant_type: "refresh_token",
|
||||||
TwitterErrorResponse,
|
refresh_token,
|
||||||
) => {
|
client_id: this.settings.clientId!,
|
||||||
if (res.error) throw new Error(res.error_description);
|
redirect_uri: `${
|
||||||
return res;
|
Config.get().cdn.endpointPrivate ||
|
||||||
},
|
"http://localhost:3001"
|
||||||
|
}/connections/${this.id}/callback`,
|
||||||
|
code_verifier: "challenge", // TODO: properly use PKCE challenge
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
.post()
|
||||||
|
.json<ConnectedAccountCommonOAuthTokenResponse>()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging code for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUser(token: string): Promise<TwitterUserResponse> {
|
async getUser(token: string): Promise<TwitterUserResponse> {
|
||||||
const url = new URL(this.userInfoUrl);
|
const url = new URL(this.userInfoUrl);
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "GET",
|
.headers({
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error fetching user for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ApiError,
|
|
||||||
Config,
|
Config,
|
||||||
ConnectedAccount,
|
ConnectedAccount,
|
||||||
ConnectedAccountCommonOAuthTokenResponse,
|
ConnectedAccountCommonOAuthTokenResponse,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
ConnectionLoader,
|
ConnectionLoader,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
} from "@fosscord/util";
|
} from "@fosscord/util";
|
||||||
import fetch from "node-fetch";
|
import wretch from "wretch";
|
||||||
import Connection from "../../util/connections/Connection";
|
import Connection from "../../util/connections/Connection";
|
||||||
import { XboxSettings } from "./XboxSettings";
|
import { XboxSettings } from "./XboxSettings";
|
||||||
|
|
||||||
@ -76,36 +75,28 @@ export default class XboxConnection extends Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getUserToken(token: string): Promise<string> {
|
async getUserToken(token: string): Promise<string> {
|
||||||
return fetch(this.userAuthUrl, {
|
return wretch(this.userAuthUrl)
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
"x-xbl-contract-version": "3",
|
"x-xbl-contract-version": "3",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Accept: "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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error getting user token for ${this.id} connection: ${e}`,
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
);
|
|
||||||
throw DiscordApiErrors.INVALID_OAUTH_TOKEN;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,82 +108,57 @@ export default class XboxConnection extends Connection {
|
|||||||
|
|
||||||
const url = this.getTokenUrl();
|
const url = this.getTokenUrl();
|
||||||
|
|
||||||
return fetch(url.toString(), {
|
return wretch(url.toString())
|
||||||
method: "POST",
|
.headers({
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
Authorization: `Basic ${Buffer.from(
|
Authorization: `Basic ${Buffer.from(
|
||||||
`${this.settings.clientId!}:${this.settings.clientSecret!}`,
|
`${this.settings.clientId!}:${this.settings.clientSecret!}`,
|
||||||
).toString("base64")}`,
|
).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(
|
.body(
|
||||||
(
|
new URLSearchParams({
|
||||||
res: ConnectedAccountCommonOAuthTokenResponse &
|
grant_type: "authorization_code",
|
||||||
XboxErrorResponse,
|
code: code,
|
||||||
) => {
|
client_id: this.settings.clientId!,
|
||||||
if (res.error) throw new Error(res.error_description);
|
redirect_uri: `${
|
||||||
return res;
|
Config.get().cdn.endpointPrivate ||
|
||||||
},
|
"http://localhost:3001"
|
||||||
|
}/connections/${this.id}/callback`,
|
||||||
|
scope: this.scopes.join(" "),
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
.post()
|
||||||
|
.json<ConnectedAccountCommonOAuthTokenResponse>()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error exchanging code for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUser(token: string): Promise<XboxUserResponse> {
|
async getUser(token: string): Promise<XboxUserResponse> {
|
||||||
const url = new URL(this.userInfoUrl);
|
const url = new URL(this.userInfoUrl);
|
||||||
return fetch(url.toString(), {
|
|
||||||
method: "POST",
|
return wretch(url.toString())
|
||||||
headers: {
|
.headers({
|
||||||
"x-xbl-contract-version": "3",
|
"x-xbl-contract-version": "3",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Accept: "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) => {
|
.catch((e) => {
|
||||||
console.error(
|
console.error(e);
|
||||||
`Error fetching user for ${this.id} connection: ${e}`,
|
|
||||||
);
|
|
||||||
throw DiscordApiErrors.GENERAL_ERROR;
|
throw DiscordApiErrors.GENERAL_ERROR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user