diff --git a/bsg-frontend/apps/extension/.env.example b/bsg-frontend/apps/extension/.env.example new file mode 100644 index 0000000..1a54794 --- /dev/null +++ b/bsg-frontend/apps/extension/.env.example @@ -0,0 +1,11 @@ +# Firebase Configuration +# Copy this file to .env.local and fill in your Firebase project values +# Get these values from Firebase Console > Project Settings + +NEXT_PUBLIC_FIREBASE_API_KEY= +NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN= +NEXT_PUBLIC_FIREBASE_PROJECT_ID= +NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET= +NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID= +NEXT_PUBLIC_FIREBASE_APP_ID= +NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID= diff --git a/bsg-frontend/apps/extension/.gitignore b/bsg-frontend/apps/extension/.gitignore new file mode 100644 index 0000000..aeb662c --- /dev/null +++ b/bsg-frontend/apps/extension/.gitignore @@ -0,0 +1,6 @@ +.* +!.gitignore +!.env.example +.env.local +.env +/out \ No newline at end of file diff --git a/bsg-frontend/apps/extension/firebase/auth/signIn/googleImplementation/chromeExtensionAuth.ts b/bsg-frontend/apps/extension/firebase/auth/signIn/googleImplementation/chromeExtensionAuth.ts new file mode 100644 index 0000000..e9bae46 --- /dev/null +++ b/bsg-frontend/apps/extension/firebase/auth/signIn/googleImplementation/chromeExtensionAuth.ts @@ -0,0 +1,100 @@ +import { app } from "../../../config"; +import { getAuth, signInWithCredential, GoogleAuthProvider, User } from "firebase/auth"; + +const auth = getAuth(app); + +export async function SignInWithChromeIdentity(): Promise { + return new Promise((resolve, reject) => { + if (!chrome.identity) { + reject(new Error('Chrome identity API not available')); + return; + } + + chrome.identity.getAuthToken({ interactive: true }, async (token) => { + if (chrome.runtime.lastError) { + reject(new Error(chrome.runtime.lastError.message)); + return; + } + + if (!token || typeof token !== 'string') { + reject(new Error('No valid token received')); + return; + } + + try { + // Use the token to get user info from Google API + //const userInfo = await getUserInfoFromToken(token); + + // Create a Firebase credential using the token + const credential = GoogleAuthProvider.credential(null, token); + + // Sign in to Firebase with the credential + const result = await signInWithCredential(auth, credential); + + resolve(result.user); + } catch (error) { + console.error('Firebase auth error:', error); + reject(error); + } + }); + }); +} + +async function getUserInfoFromToken(token: string) { + const response = await fetch(`https://www.googleapis.com/oauth2/v2/userinfo?access_token=${token}`); + if (!response.ok) { + throw new Error('Failed to get user info'); + } + return response.json(); +} + +export async function SignOutFromChrome(): Promise { + + return new Promise((resolve, reject) => { + if (!chrome.identity) { + reject(new Error('Chrome identity API not available')); + return; + } + + chrome.identity.getAuthToken({ interactive: false }, (token) => { + + const tokenToRevoke = token.toString(); + const requestBody = new URLSearchParams({ + token: tokenToRevoke, + }).toString(); + + fetch('https://oauth2.googleapis.com/revoke', { + method:'POST', + headers:{ + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: requestBody, + + }).then(response =>{ + if(response.ok){ + console.log("Reached google servers") + + chrome.identity.clearAllCachedAuthTokens(() => { + auth.signOut().then(resolve).catch(reject); + } + ) + + } + else { + console.error('Error revoking token', response.status, response.statusText) + reject(new Error(`Failed to revoke token: ${response.statusText}`)) + } + } + ).catch(error => { + console.error("Network Error during token revocation", error) + reject(error); + }) + + + }); + + + }); + + +} \ No newline at end of file diff --git a/bsg-frontend/apps/extension/firebase/auth/signIn/googleImplementation/googleAuth.ts b/bsg-frontend/apps/extension/firebase/auth/signIn/googleImplementation/googleAuth.ts new file mode 100644 index 0000000..012945d --- /dev/null +++ b/bsg-frontend/apps/extension/firebase/auth/signIn/googleImplementation/googleAuth.ts @@ -0,0 +1,60 @@ +import { app } from "../../../config"; +import { getAuth, + signInWithRedirect, + signInWithPopup, + getRedirectResult, + User, + } from "firebase/auth"; + +import { provider } from './googleSignIn'; + + +const auth = getAuth(app); + + +export async function SignInWithGoogleRedirect(): Promise { + + try{ + await signInWithRedirect(auth, provider); + } + catch(error){ + console.error("Auth error: ", error); + console.error(error.message); + throw error; + } + } + +export async function SignInWithGooglePopup(): Promise { + try { + const result = await signInWithPopup(auth, provider); + return result.user; + } catch (error) { + console.error("Popup auth error: ", error); + throw error; + } +} + +export async function HandleAuthRedirectedResult(): Promise{ + + try{ + + const result = await getRedirectResult(auth, provider); + + if(result){ + return result.user; + }else { + throw new Error("User Does Not Exist"); + } + + }catch(error){ + console.log(error) + console.log(error.message) + + throw new Error("User Did Not Successfully Log In") + + + } + +} + + diff --git a/bsg-frontend/apps/extension/firebase/auth/signIn/googleImplementation/googleSignIn.ts b/bsg-frontend/apps/extension/firebase/auth/signIn/googleImplementation/googleSignIn.ts new file mode 100644 index 0000000..d91093e --- /dev/null +++ b/bsg-frontend/apps/extension/firebase/auth/signIn/googleImplementation/googleSignIn.ts @@ -0,0 +1,10 @@ +import { GoogleAuthProvider } from 'firebase/auth'; + + +export const provider = new GoogleAuthProvider(); +console.log(provider) + + + + + diff --git a/bsg-frontend/apps/extension/firebase/auth/signOut.ts b/bsg-frontend/apps/extension/firebase/auth/signOut.ts new file mode 100644 index 0000000..65b8366 --- /dev/null +++ b/bsg-frontend/apps/extension/firebase/auth/signOut.ts @@ -0,0 +1,19 @@ +import { signOut, getAuth } from "firebase/auth"; +import { app } from "../config"; + + +export async function signOutOfAccount(): Promise{ + + const auth = getAuth(app); + + try{ + return await signOut(auth); + + }catch(error){ + + console.log(error.code) + console.log(error.message) + throw error; + } + +} \ No newline at end of file diff --git a/bsg-frontend/apps/extension/firebase/config.ts b/bsg-frontend/apps/extension/firebase/config.ts new file mode 100644 index 0000000..7b329b5 --- /dev/null +++ b/bsg-frontend/apps/extension/firebase/config.ts @@ -0,0 +1,24 @@ +// Import the functions you need from the SDKs you need +import { initializeApp } from "firebase/app"; +import { getAuth, setPersistence, browserSessionPersistence } from "firebase/auth"; + + + +const firebaseConfig = { + apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, + authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, + projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, + storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, + appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, + measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID +}; + +// Initialize Firebase +export const app = initializeApp(firebaseConfig); + +// Initialize Auth with session persistence +export const auth = getAuth(app); +setPersistence(auth, browserSessionPersistence); + + diff --git a/bsg-frontend/apps/extension/hooks/useNewTab.ts b/bsg-frontend/apps/extension/hooks/useNewTab.ts new file mode 100644 index 0000000..c1e611e --- /dev/null +++ b/bsg-frontend/apps/extension/hooks/useNewTab.ts @@ -0,0 +1,9 @@ +import { useCallback } from 'react'; + +export const useNewTab = () => { + const openInNewTab = useCallback((url: string) => { + chrome.tabs.create({ url }); + }, []); + + return { openInNewTab }; +}; \ No newline at end of file diff --git a/bsg-frontend/apps/extension/next.config.js b/bsg-frontend/apps/extension/next.config.js index b32fe2c..1e750ae 100644 --- a/bsg-frontend/apps/extension/next.config.js +++ b/bsg-frontend/apps/extension/next.config.js @@ -11,4 +11,8 @@ module.exports = { '@bsg/ui-styles', ], + //no need for this line extension does not user next/image components + // images: { + // unoptimized: true, + // }, } diff --git a/bsg-frontend/apps/extension/out/404.html b/bsg-frontend/apps/extension/out/404.html deleted file mode 100644 index cc77d41..0000000 --- a/bsg-frontend/apps/extension/out/404.html +++ /dev/null @@ -1 +0,0 @@ -404: This page could not be found

404

This page could not be found.

\ No newline at end of file diff --git a/bsg-frontend/apps/extension/out/defaultPopup.html b/bsg-frontend/apps/extension/out/defaultPopup.html deleted file mode 100644 index d31352f..0000000 --- a/bsg-frontend/apps/extension/out/defaultPopup.html +++ /dev/null @@ -1 +0,0 @@ -
Loading...
\ No newline at end of file diff --git a/bsg-frontend/apps/extension/out/manifest.json b/bsg-frontend/apps/extension/out/manifest.json deleted file mode 100644 index fde882f..0000000 --- a/bsg-frontend/apps/extension/out/manifest.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "manifest_version": 3, - "name": "BSG", - "version": "1.0.0", - "permissions": [ - "tabs" - ], - "action": { - "default_popup": "defaultPopup.html" - }, - "content_security_policy": { - "extension_pages": "script-src 'self'; object-src 'self';" - }, - "web_accessible_resources": [ - { - "resources": [ - "defaultPopup.html", - "next/*", - "logIn.html" - ], - "matches": [ - "" - ] - } - ], - "content_scripts": [ - { - "matches": [ - "https://leetcode.com/problems/*", - "https://*.leetcode.com/problems/*" - ], - "js": [ - "contentScript.js" - ], - "run_at": "document_idle" - } - ] -} diff --git a/bsg-frontend/apps/extension/out/next/static/chunks/polyfills-c67a75d1b6f99dc8.js b/bsg-frontend/apps/extension/out/next/static/chunks/polyfills-c67a75d1b6f99dc8.js deleted file mode 100644 index 3858b79..0000000 --- a/bsg-frontend/apps/extension/out/next/static/chunks/polyfills-c67a75d1b6f99dc8.js +++ /dev/null @@ -1 +0,0 @@ -!function(){var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function e(t){var e={exports:{}};return t(e,e.exports),e.exports}var r=function(t){return t&&t.Math==Math&&t},n=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof t&&t)||Function("return this")(),o=function(t){try{return!!t()}catch(t){return!0}},i=!o(function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}),a={}.propertyIsEnumerable,u=Object.getOwnPropertyDescriptor,s=u&&!a.call({1:2},1)?function(t){var e=u(this,t);return!!e&&e.enumerable}:a,c={f:s},f=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}},l={}.toString,h=function(t){return l.call(t).slice(8,-1)},p="".split,d=o(function(){return!Object("z").propertyIsEnumerable(0)})?function(t){return"String"==h(t)?p.call(t,""):Object(t)}:Object,v=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t},g=function(t){return d(v(t))},y=function(t){return"object"==typeof t?null!==t:"function"==typeof t},m=function(t,e){if(!y(t))return t;var r,n;if(e&&"function"==typeof(r=t.toString)&&!y(n=r.call(t)))return n;if("function"==typeof(r=t.valueOf)&&!y(n=r.call(t)))return n;if(!e&&"function"==typeof(r=t.toString)&&!y(n=r.call(t)))return n;throw TypeError("Can't convert object to primitive value")},b={}.hasOwnProperty,w=function(t,e){return b.call(t,e)},S=n.document,E=y(S)&&y(S.createElement),x=function(t){return E?S.createElement(t):{}},A=!i&&!o(function(){return 7!=Object.defineProperty(x("div"),"a",{get:function(){return 7}}).a}),O=Object.getOwnPropertyDescriptor,R={f:i?O:function(t,e){if(t=g(t),e=m(e,!0),A)try{return O(t,e)}catch(t){}if(w(t,e))return f(!c.f.call(t,e),t[e])}},j=function(t){if(!y(t))throw TypeError(String(t)+" is not an object");return t},P=Object.defineProperty,I={f:i?P:function(t,e,r){if(j(t),e=m(e,!0),j(r),A)try{return P(t,e,r)}catch(t){}if("get"in r||"set"in r)throw TypeError("Accessors not supported");return"value"in r&&(t[e]=r.value),t}},T=i?function(t,e,r){return I.f(t,e,f(1,r))}:function(t,e,r){return t[e]=r,t},k=function(t,e){try{T(n,t,e)}catch(r){n[t]=e}return e},L="__core-js_shared__",U=n[L]||k(L,{}),M=Function.toString;"function"!=typeof U.inspectSource&&(U.inspectSource=function(t){return M.call(t)});var _,N,C,F=U.inspectSource,B=n.WeakMap,D="function"==typeof B&&/native code/.test(F(B)),q=!1,z=e(function(t){(t.exports=function(t,e){return U[t]||(U[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.6.5",mode:"global",copyright:"© 2020 Denis Pushkarev (zloirock.ru)"})}),W=0,K=Math.random(),G=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++W+K).toString(36)},$=z("keys"),V=function(t){return $[t]||($[t]=G(t))},H={};if(D){var X=new(0,n.WeakMap),Y=X.get,J=X.has,Q=X.set;_=function(t,e){return Q.call(X,t,e),e},N=function(t){return Y.call(X,t)||{}},C=function(t){return J.call(X,t)}}else{var Z=V("state");H[Z]=!0,_=function(t,e){return T(t,Z,e),e},N=function(t){return w(t,Z)?t[Z]:{}},C=function(t){return w(t,Z)}}var tt,et={set:_,get:N,has:C,enforce:function(t){return C(t)?N(t):_(t,{})},getterFor:function(t){return function(e){var r;if(!y(e)||(r=N(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return r}}},rt=e(function(t){var e=et.get,r=et.enforce,o=String(String).split("String");(t.exports=function(t,e,i,a){var u=!!a&&!!a.unsafe,s=!!a&&!!a.enumerable,c=!!a&&!!a.noTargetGet;"function"==typeof i&&("string"!=typeof e||w(i,"name")||T(i,"name",e),r(i).source=o.join("string"==typeof e?e:"")),t!==n?(u?!c&&t[e]&&(s=!0):delete t[e],s?t[e]=i:T(t,e,i)):s?t[e]=i:k(e,i)})(Function.prototype,"toString",function(){return"function"==typeof this&&e(this).source||F(this)})}),nt=n,ot=function(t){return"function"==typeof t?t:void 0},it=function(t,e){return arguments.length<2?ot(nt[t])||ot(n[t]):nt[t]&&nt[t][e]||n[t]&&n[t][e]},at=Math.ceil,ut=Math.floor,st=function(t){return isNaN(t=+t)?0:(t>0?ut:at)(t)},ct=Math.min,ft=function(t){return t>0?ct(st(t),9007199254740991):0},lt=Math.max,ht=Math.min,pt=function(t,e){var r=st(t);return r<0?lt(r+e,0):ht(r,e)},dt=function(t){return function(e,r,n){var o,i=g(e),a=ft(i.length),u=pt(n,a);if(t&&r!=r){for(;a>u;)if((o=i[u++])!=o)return!0}else for(;a>u;u++)if((t||u in i)&&i[u]===r)return t||u||0;return!t&&-1}},vt={includes:dt(!0),indexOf:dt(!1)},gt=vt.indexOf,yt=function(t,e){var r,n=g(t),o=0,i=[];for(r in n)!w(H,r)&&w(n,r)&&i.push(r);for(;e.length>o;)w(n,r=e[o++])&&(~gt(i,r)||i.push(r));return i},mt=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],bt=mt.concat("length","prototype"),wt={f:Object.getOwnPropertyNames||function(t){return yt(t,bt)}},St={f:Object.getOwnPropertySymbols},Et=it("Reflect","ownKeys")||function(t){var e=wt.f(j(t)),r=St.f;return r?e.concat(r(t)):e},xt=function(t,e){for(var r=Et(e),n=I.f,o=R.f,i=0;i2?arguments[2]:void 0,u=Mt((void 0===a?n:pt(a,n))-i,n-o),s=1;for(i0;)i in r?r[o]=r[i]:delete r[o],o+=s,i+=s;return r},Nt=!!Object.getOwnPropertySymbols&&!o(function(){return!String(Symbol())}),Ct=Nt&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,Ft=z("wks"),Bt=n.Symbol,Dt=Ct?Bt:Bt&&Bt.withoutSetter||G,qt=function(t){return w(Ft,t)||(Ft[t]=Nt&&w(Bt,t)?Bt[t]:Dt("Symbol."+t)),Ft[t]},zt=Object.keys||function(t){return yt(t,mt)},Wt=i?Object.defineProperties:function(t,e){j(t);for(var r,n=zt(e),o=n.length,i=0;o>i;)I.f(t,r=n[i++],e[r]);return t},Kt=it("document","documentElement"),Gt=V("IE_PROTO"),$t=function(){},Vt=function(t){return"