From 62a6f0d94e8fda9636a8b4697a933370e30e8669 Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Thu, 11 Apr 2024 22:37:59 -0400 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20#84=20Support=20custom=20oa?= =?UTF-8?q?uth=20app?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes: #84 --- src/github/auth.ts | 6 ++-- src/settings/account.ts | 70 ++++++++++++++++++++++++++++++++++-- src/settings/settings-tab.ts | 4 +++ src/settings/types.ts | 2 ++ 4 files changed, 77 insertions(+), 5 deletions(-) diff --git a/src/github/auth.ts b/src/github/auth.ts index fd817e5..af9b990 100644 --- a/src/github/auth.ts +++ b/src/github/auth.ts @@ -4,6 +4,8 @@ import { createOAuthDeviceAuth } from "@octokit/auth-oauth-device"; import { request } from "@octokit/request"; import { requestUrl } from "obsidian"; +const defaultClientId = "baf0370cb98e1387d244"; + function getHeaders(headers: HeadersInit | undefined): Record | undefined { if (!headers) { return undefined; @@ -71,10 +73,10 @@ async function doFetch(url: RequestInfo | URL, options?: RequestInit | undefined return partialResult as Response; } -export const auth = (verificationHandler: OnVerificationCallback) => +export const auth = (verificationHandler: OnVerificationCallback, clientId: string = defaultClientId) => createOAuthDeviceAuth({ clientType: "oauth-app", - clientId: "baf0370cb98e1387d244", + clientId, scopes: ["repo"], onVerification: verificationHandler, request: request.defaults({ diff --git a/src/settings/account.ts b/src/settings/account.ts index 6786caa..146db16 100644 --- a/src/settings/account.ts +++ b/src/settings/account.ts @@ -27,7 +27,9 @@ export class AccountSettings { container: HTMLElement, saveNewAccountCallback: (account: GithubAccount) => Promise, ): void { - this.newAccount = { id: crypto.randomUUID(), name: "", orgs: [], token: "" }; + if (!this.newAccount) { + this.newAccount = { id: crypto.randomUUID(), name: "", orgs: [], token: "", customOAuth: false }; + } // TODO: Combine the new account and existing account rendering to reduce duplication const accountContainer = container.createDiv(); const header = accountContainer.createEl("h3", { text: "New account" }); @@ -63,6 +65,36 @@ export class AccountSettings { }); }); + const oauthDesc = createFragment((fragment) => { + fragment.appendText( + "You can optionally provide your own OAuth app for more control and a larger request rate limit. See the ", + ); + fragment.createEl("a", { + text: "plugin documentation", + href: "https://github.com/nathonius/obsidian-github-link/wiki/Authentication#custom-oauth-app", + }); + fragment.appendText(" for instructions."); + }); + const customOAuthSetting = new Setting(accountContainer) + .setName("Use custom OAuth app") + .setDesc(oauthDesc) + .addToggle((toggle) => { + toggle.setValue(this.newAccount!.customOAuth ?? false); + toggle.onChange((value) => { + this.newAccount!.customOAuth = value; + this.displayCallback(); + }); + }); + if (this.newAccount.customOAuth) { + customOAuthSetting.addText((text) => { + text.setValue(this.newAccount!.clientId ?? ""); + text.setPlaceholder("Client ID"); + text.onChange((value) => { + this.newAccount!.clientId = value; + }); + }); + } + new Setting(accountContainer) .setName("Token") .setDesc( @@ -93,7 +125,7 @@ export class AccountSettings { button.setTooltip("Save account"); button.setIcon("save"); button.onClick(async () => { - if (!this.newAccount?.name || !this.newAccount.token) { + if (!this.newAccount?.name) { return; } await saveNewAccountCallback(this.newAccount); @@ -137,6 +169,34 @@ export class AccountSettings { }); }); + const oauthDesc = createFragment((fragment) => { + fragment.appendText( + "You can optionally provide your own OAuth app for more control and a larger request rate limit. See the ", + ); + fragment.createEl("a", { text: "plugin documentation", href: "#" }); + fragment.appendText(" for instructions."); + }); + const customOAuthSetting = new Setting(accountContainer) + .setName("Use custom OAuth app") + .setDesc(oauthDesc) + .addToggle((toggle) => { + toggle.setValue(account.customOAuth ?? false); + toggle.onChange((value) => { + account.customOAuth = value; + this.displayCallback(); + }); + }); + if (account.customOAuth) { + customOAuthSetting.addText((text) => { + text.setValue(account.clientId ?? ""); + text.setPlaceholder("Client ID"); + text.onChange((value) => { + account.clientId = value; + this.saveCallback(); + }); + }); + } + new Setting(accountContainer) .setName("Token") .setDesc( @@ -145,7 +205,11 @@ export class AccountSettings { .addButton((button) => { button.setButtonText("Generate Token"); button.onClick(async () => { - const authResult = await auth(this.tokenVerification.bind(this))({ + const customClientId = account.customOAuth ? account.clientId : undefined; + const authResult = await auth( + this.tokenVerification.bind(this), + customClientId, + )({ type: "oauth", }); this.authModal?.close(); diff --git a/src/settings/settings-tab.ts b/src/settings/settings-tab.ts index 77b2753..4fe682f 100644 --- a/src/settings/settings-tab.ts +++ b/src/settings/settings-tab.ts @@ -43,6 +43,10 @@ export class GithubLinkPluginSettingsTab extends PluginSettingTab { }); }); + if (this.accountSettings.newAccount) { + this.accountSettings.renderNewAccount(newAccountSection, this.saveNewAccount.bind(this)); + } + new Setting(containerEl) .setName("Default account") .setDesc("The account that will be used if no other users or organizations match.") diff --git a/src/settings/types.ts b/src/settings/types.ts index 1e6a328..0f7f4b5 100644 --- a/src/settings/types.ts +++ b/src/settings/types.ts @@ -5,6 +5,8 @@ export interface GithubAccount { name: string; orgs: string[]; token: string; + customOAuth?: boolean; + clientId?: string; } export interface GithubLinkPluginData {