diff options
author | Madeline <46743919+MaddyUnderStars@users.noreply.github.com> | 2023-04-02 11:30:31 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-02 11:30:31 +1000 |
commit | 86ac90b1e4e83cb1f55c45055d9ab3a488fe67bd (patch) | |
tree | 83c97c8d7464bbfb0b1924597f1dde8c69528ba9 /src/connections/GitHub | |
parent | Remove ALL fosscord mentions (diff) | |
parent | Less spammy user connection logs (diff) | |
download | server-86ac90b1e4e83cb1f55c45055d9ab3a488fe67bd.tar.xz |
Merge pull request #1009 from Puyodead1/refactor/dev/connections
Connections Part 1
Diffstat (limited to 'src/connections/GitHub')
-rw-r--r-- | src/connections/GitHub/GitHubSettings.ts | 5 | ||||
-rw-r--r-- | src/connections/GitHub/index.ts | 106 |
2 files changed, 111 insertions, 0 deletions
diff --git a/src/connections/GitHub/GitHubSettings.ts b/src/connections/GitHub/GitHubSettings.ts new file mode 100644 index 00000000..1b4070d2 --- /dev/null +++ b/src/connections/GitHub/GitHubSettings.ts @@ -0,0 +1,5 @@ +export class GitHubSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts new file mode 100644 index 00000000..638a34af --- /dev/null +++ b/src/connections/GitHub/index.ts @@ -0,0 +1,106 @@ +import { + ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@spacebar/util"; +import wretch from "wretch"; +import Connection from "../../util/connections/Connection"; +import { GitHubSettings } from "./GitHubSettings"; + +interface UserResponse { + login: string; + id: number; + name: string; +} + +export default class GitHubConnection extends Connection { + public readonly id = "github"; + public readonly authorizeUrl = "https://github.com/login/oauth/authorize"; + public readonly tokenUrl = "https://github.com/login/oauth/access_token"; + public readonly userInfoUrl = "https://api.github.com/user"; + public readonly scopes = ["read:user"]; + settings: GitHubSettings = new GitHubSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as GitHubSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + url.searchParams.append("redirect_uri", this.getRedirectUri()); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + return url.toString(); + } + + getTokenUrl(code: string): string { + const url = new URL(this.tokenUrl); + url.searchParams.append("client_id", this.settings.clientId!); + url.searchParams.append("client_secret", this.settings.clientSecret!); + url.searchParams.append("code", code); + return url.toString(); + } + + async exchangeCode( + state: string, + code: string, + ): Promise<ConnectedAccountCommonOAuthTokenResponse> { + this.validateState(state); + + const url = this.getTokenUrl(code); + + return wretch(url.toString()) + .headers({ + Accept: "application/json", + }) + + .post() + .json<ConnectedAccountCommonOAuthTokenResponse>() + .catch((e) => { + console.error(e); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async getUser(token: string): Promise<UserResponse> { + const url = new URL(this.userInfoUrl); + return wretch(url.toString()) + .headers({ + Authorization: `Bearer ${token}`, + }) + .get() + .json<UserResponse>() + .catch((e) => { + console.error(e); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise<ConnectedAccount | null> { + const userId = this.getUserId(params.state); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); + + const exists = await this.hasConnection(userId, userInfo.id.toString()); + + if (exists) return null; + + return await this.createConnection({ + user_id: userId, + external_id: userInfo.id.toString(), + friend_sync: params.friend_sync, + name: userInfo.login, + type: this.id, + }); + } +} |