Get login working
This commit is contained in:
		| @ -45,6 +45,7 @@ | ||||
|     "html2canvas-pro": "^1.5.5", | ||||
|     "json-rpc-2.0": "^1.6.0", | ||||
|     "jszip": "^3.10.1", | ||||
|     "openid-client": "^5.6.5", | ||||
|     "re-resizable": "^6.9.11", | ||||
|     "react": "^18.3.1", | ||||
|     "react-dom": "^18.2.0", | ||||
| @ -149,6 +150,8 @@ | ||||
|     "@types/wait-on": "^5.3.4", | ||||
|     "@types/wicg-file-system-access": "^2023.10.5", | ||||
|     "@types/ws": "^8.5.10", | ||||
|     "@typescript-eslint/eslint-plugin": "^5.0.0", | ||||
|     "@typescript-eslint/parser": "^5.0.0", | ||||
|     "@vitejs/plugin-react": "^4.3.0", | ||||
|     "@vitest/web-worker": "^1.5.0", | ||||
|     "@wdio/cli": "^8.24.3", | ||||
| @ -177,8 +180,6 @@ | ||||
|     "tailwindcss": "^3.4.1", | ||||
|     "ts-node": "^10.0.0", | ||||
|     "typescript": "^4.5.4", | ||||
|     "@typescript-eslint/eslint-plugin": "^5.0.0", | ||||
|     "@typescript-eslint/parser": "^5.0.0", | ||||
|     "vite": "^5.0.12", | ||||
|     "vite-plugin-eslint": "^1.8.1", | ||||
|     "vite-plugin-package-version": "^1.1.0", | ||||
|  | ||||
| @ -415,10 +415,6 @@ export const setState = async ( | ||||
|   appStateStore = state | ||||
| } | ||||
|  | ||||
| export const login = () => { | ||||
|   console.log('STUB') | ||||
| } | ||||
|  | ||||
| export const getUser = async ( | ||||
|   token: string, | ||||
|   hostname: string | ||||
|  | ||||
| @ -5,6 +5,7 @@ import packageJson from '../../package.json' | ||||
|  | ||||
| const open = (args: any) => ipcRenderer.invoke('dialog', args) | ||||
| const showInFolder = (path: string) => ipcRenderer.invoke('shell.showItemInFolder', path) | ||||
| const login = (host: string) => ipcRenderer.invoke('login', host) | ||||
|  | ||||
| const readFile = (path: string) => fs.readFile(path, 'utf-8') | ||||
| const rename = (prev: string, next: string) => fs.rename(prev, next) | ||||
| @ -31,6 +32,7 @@ const exposeProcessEnv = (varName: string) => { | ||||
|  | ||||
| import('@kittycad/lib').then((kittycad) => { | ||||
|   contextBridge.exposeInMainWorld('electron', { | ||||
|     login, | ||||
|     // Passing fs directly is not recommended since it gives a lot of power | ||||
|     // to the browser side / potential malicious code. We restrict what is | ||||
|     // exported. | ||||
|  | ||||
| @ -146,10 +146,7 @@ async function getUser(context: UserContext) { | ||||
|       }) | ||||
|         .then((res) => res.json()) | ||||
|         .catch((err) => console.error('error from Browser getUser', err)) | ||||
|     : getUserDesktop( | ||||
|         'f8864550-84a6-4a06-8d3f-68d29bbe5608' /* context.token */, | ||||
|         VITE_KC_API_BASE_URL | ||||
|       ) | ||||
|     : getUserDesktop(context.token, VITE_KC_API_BASE_URL ) | ||||
|  | ||||
|   const user = await userPromise | ||||
|  | ||||
|  | ||||
							
								
								
									
										45
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								src/main.ts
									
									
									
									
									
								
							| @ -4,6 +4,7 @@ | ||||
| import { Configuration } from 'wasm-lib/kcl/bindings/Configuration' | ||||
| import { app, BrowserWindow, ipcMain, dialog, shell } from 'electron' | ||||
| import path from 'path' | ||||
| import { Issuer } from 'openid-client' | ||||
|  | ||||
| // Handle creating/removing shortcuts on Windows when installing/uninstalling. | ||||
| if (require('electron-squirrel-startup')) { | ||||
| @ -61,3 +62,47 @@ ipcMain.handle('dialog', (event, data) => { | ||||
| ipcMain.handle('shell.showItemInFolder', (event, data) => { | ||||
|   return shell.showItemInFolder(data) | ||||
| }) | ||||
|  | ||||
| ipcMain.handle('login', async (event, host) => { | ||||
|     console.log('Logging in...') | ||||
|     // Do an OAuth 2.0 Device Authorization Grant dance to get a token. | ||||
|     const issuer = new Issuer({ | ||||
|       device_authorization_endpoint: `${host}/oauth2/device/auth`, | ||||
|       token_endpoint: `${host}/oauth2/device/token`, | ||||
|     }) | ||||
|     const client = new issuer.Client({ | ||||
|       // We can hardcode the client ID. | ||||
|       // This value is safe to be embedded in version control. | ||||
|       // This is the client ID of the KittyCAD app. | ||||
|       client_id: "2af127fb-e14e-400a-9c57-a9ed08d1a5b7", | ||||
|       token_endpoint_auth_method: 'none', | ||||
|     }) | ||||
|  | ||||
|     const handle = await client.deviceAuthorization() | ||||
|  | ||||
|     // Open the system browser with the auth_uri. | ||||
|     // We do this in the browser and not a separate window because we want 1password and | ||||
|     // other crap to work well. | ||||
|     // TODO: find a better way to share this value with tauri e2e tests | ||||
|     // Here we're using an env var to enable the /tmp file (windows not supported for now) | ||||
|     // and bypass the shell::open call as it fails on GitHub Actions. | ||||
|     const e2e_tauri_enabled = process.env.E2E_TAURI_ENABLED | ||||
|     if (e2e_tauri_enabled) { | ||||
|         console.warn(`E2E_TAURI_ENABLED is set, won't open ${handle.verification_uri_complete} externally`) | ||||
|         let temp = '/tmp' | ||||
|         // Overwrite with Windows variable | ||||
|         if (process.env.TEMP) { | ||||
|           temp = process.env.TEMP | ||||
|         } | ||||
|         let path = path.join(temp, "kittycad_user_code") | ||||
|         console.log(`Writing to ${path}`) | ||||
|         await fs.writeFile(path, handle.user_code) | ||||
|     } else { | ||||
|         shell.openExternal(handle.verification_uri_complete) | ||||
|     } | ||||
|  | ||||
|     // Wait for the user to login. | ||||
|     const tokenSet = await handle.poll() | ||||
|  | ||||
|     return tokenSet | ||||
| }) | ||||
|  | ||||
| @ -5,7 +5,6 @@ import { Themes, getSystemTheme } from '../lib/theme' | ||||
| import { paths } from 'lib/paths' | ||||
| import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' | ||||
| import { APP_NAME } from 'lib/constants' | ||||
| import { login } from 'lib/desktop' | ||||
|  | ||||
| const SignIn = () => { | ||||
|   const { | ||||
| @ -25,10 +24,10 @@ const SignIn = () => { | ||||
|       ? '-dark' | ||||
|       : '' | ||||
|  | ||||
|   const signInTauri = async () => { | ||||
|   const signInDesktop = async () => { | ||||
|     // We want to invoke our command to login via device auth. | ||||
|     try { | ||||
|       const token: string = await login(VITE_KC_API_BASE_URL) | ||||
|       const token: string = await window.electron.login(VITE_KC_API_BASE_URL) | ||||
|       send({ type: 'Log in', token }) | ||||
|     } catch (error) { | ||||
|       console.error('Error with login button', error) | ||||
| @ -64,7 +63,7 @@ const SignIn = () => { | ||||
|         {isDesktop() ? ( | ||||
|           <ActionButton | ||||
|             Element="button" | ||||
|             onClick={signInTauri} | ||||
|             onClick={signInDesktop} | ||||
|             iconStart={{ icon: 'arrowRight' }} | ||||
|             className="w-fit mt-4" | ||||
|             data-testid="sign-in-button" | ||||
|  | ||||
		Reference in New Issue
	
	Block a user