Skip to content

Commit

Permalink
feat: Login with pkce (#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
Anush008 authored Jul 28, 2023
1 parent e95e7a1 commit 42e8d4a
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 14 deletions.
3 changes: 2 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// OpenSauced constants
export const OPEN_SAUCED_INSIGHTS_DOMAIN = import.meta.env.VITE_OPEN_SAUCED_INSIGHTS_DOMAIN;
export const OPEN_SAUCED_API_ENDPOINT = import.meta.env.VITE_OPEN_SAUCED_API_ENDPOINT;
export const SUPABASE_LOGIN_URL = `https://${import.meta.env.VITE_OPEN_SAUCED_SUPABASE_ID}.supabase.co/auth/v1/authorize?provider=github&redirect_to=https://${OPEN_SAUCED_INSIGHTS_DOMAIN}/`;
export const SUPABASE_LOGIN_URL = `https://${import.meta.env.VITE_OPEN_SAUCED_SUPABASE_ID}.supabase.co/auth/v1/authorize`;


export const SUPABASE_AUTH_COOKIE_NAME = `sb-${import.meta.env.VITE_OPEN_SAUCED_SUPABASE_ID}-auth-token`;
export const SUPABASE_PKCE_VERIFIER_COOKIE_NAME = `sb-${import.meta.env.VITE_OPEN_SAUCED_SUPABASE_ID}-auth-token-code-verifier`;
export const OPEN_SAUCED_AUTH_TOKEN_KEY = "os-access-token";
export const OPEN_SAUCED_OPTED_LOG_OUT_KEY = "opted-log-out";
export const AI_PR_DESCRIPTION_CONFIG_KEY = "ai-pr-description-config";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import {
SUPABASE_LOGIN_URL,
GITHUB_PR_SUGGESTION_TEXT_AREA_SELECTOR,
} from "../../../constants";
import { GITHUB_PR_SUGGESTION_TEXT_AREA_SELECTOR } from "../../../constants";
import { insertTextAtCursor } from "../../../utils/ai-utils/cursorPositionInsert";
import {
DescriptionConfig,
getAIDescriptionConfig,
} from "../../../utils/ai-utils/descriptionconfig";
import { getAuthToken, isLoggedIn } from "../../../utils/checkAuthentication";
import { getAuthToken, isLoggedIn, optLogIn } from "../../../utils/checkAuthentication";
import { createHtmlElement } from "../../../utils/createHtmlElement";
import { isOutOfContextBounds } from "../../../utils/fetchGithubAPIData";

Expand Down Expand Up @@ -73,7 +70,7 @@ const handleSubmit = async (

try {
if (!(await isLoggedIn())) {
return window.open(SUPABASE_LOGIN_URL, "_blank");
return void optLogIn();
}

if (!logo || !button) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import openSaucedLogoIcon from "../../../assets/opensauced-icon.svg";
import { getPullRequestAPIURL } from "../../../utils/urlMatchers";
import { getDescriptionContext, isOutOfContextBounds } from "../../../utils/fetchGithubAPIData";
import { generateDescription } from "../../../utils/ai-utils/openai";
import { GITHUB_PR_COMMENT_TEXT_AREA_SELECTOR, SUPABASE_LOGIN_URL } from "../../../constants";
import { GITHUB_PR_COMMENT_TEXT_AREA_SELECTOR } from "../../../constants";
import { insertTextAtCursor } from "../../../utils/ai-utils/cursorPositionInsert";
import { getAIDescriptionConfig } from "../../../utils/ai-utils/descriptionconfig";
import { getAuthToken, isLoggedIn } from "../../../utils/checkAuthentication";
import { getAuthToken, isLoggedIn, optLogIn } from "../../../utils/checkAuthentication";

export const DescriptionGeneratorButton = () => {
const descriptionGeneratorButton = createHtmlElement("a", {
Expand All @@ -27,7 +27,7 @@ const handleSubmit = async () => {

try {
if (!(await isLoggedIn())) {
return window.open(SUPABASE_LOGIN_URL, "_blank");
return void optLogIn();
}

if (!logo || !button) {
Expand Down
60 changes: 56 additions & 4 deletions src/utils/checkAuthentication.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {
OPEN_SAUCED_AUTH_TOKEN_KEY,
OPEN_SAUCED_OPTED_LOG_OUT_KEY, SUPABASE_LOGIN_URL,
OPEN_SAUCED_INSIGHTS_DOMAIN,
OPEN_SAUCED_OPTED_LOG_OUT_KEY, SUPABASE_LOGIN_URL, SUPABASE_PKCE_VERIFIER_COOKIE_NAME,
} from "../constants";


export const isLoggedIn = async (): Promise<boolean> => Object.entries(await chrome.storage.sync.get(OPEN_SAUCED_AUTH_TOKEN_KEY)).length !== 0;

export const getAuthToken = async (): Promise<string> => (await chrome.storage.sync.get(OPEN_SAUCED_AUTH_TOKEN_KEY))[OPEN_SAUCED_AUTH_TOKEN_KEY];
Expand All @@ -13,14 +13,66 @@ export const optLogOut = () => {
void chrome.storage.local.set({ [OPEN_SAUCED_OPTED_LOG_OUT_KEY]: true });
};

export const optLogIn = () => {
export const optLogIn = async () => {
if (typeof window === "undefined") {
return;
}
void chrome.storage.local.set({ [OPEN_SAUCED_OPTED_LOG_OUT_KEY]: false });
window.open(SUPABASE_LOGIN_URL, "_blank");

const verifier = generatePKCEVerifier();
const challenge = await generatePKCEChallenge(verifier);

const loginURL = new URL(SUPABASE_LOGIN_URL);

loginURL.searchParams.append("provider", "github");
loginURL.searchParams.append(
"redirect_to",
`https://${OPEN_SAUCED_INSIGHTS_DOMAIN}`,
);
loginURL.searchParams.append("code_challenge_method", "s256");
loginURL.searchParams.append("code_challenge", challenge);

await chrome.cookies.set({
url: `https://${OPEN_SAUCED_INSIGHTS_DOMAIN}`,
name: SUPABASE_PKCE_VERIFIER_COOKIE_NAME,
value: verifier,
});
window.open(loginURL, "_blank");
};

export const hasOptedLogOut = async (): Promise<boolean> => (await chrome.storage.local.get(OPEN_SAUCED_OPTED_LOG_OUT_KEY))[OPEN_SAUCED_OPTED_LOG_OUT_KEY] === true;

export const removeAuthTokenFromStorage = async (): Promise<void> => chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY);

// Custom browser only PKCE implementation based on https://github.com/supabase/gotrue-js

const dec2hex = (dec: number) => (`0${dec.toString(16)}`).substring(-2);

const generatePKCEVerifier = () => {
const verifierLength = 56;
const array = new Uint32Array(verifierLength);

crypto.getRandomValues(array);
return Array.from(array, dec2hex).join("");
};

const sha256 = async (randomString: string) => {
const encoder = (new TextEncoder);
const encodedData = encoder.encode(randomString);
const hash = await window.crypto.subtle.digest("SHA-256", encodedData);
const bytes = new Uint8Array(hash);

return Array.from(bytes)
.map(c => String.fromCharCode(c))
.join("");
};

const base64urlencode = (str: string) => btoa(str).replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/[=]+$/, "");

const generatePKCEChallenge = async (verifier: string) => {
const hashed = await sha256(verifier);

return base64urlencode(hashed);
};

0 comments on commit 42e8d4a

Please sign in to comment.