Get login working

This commit is contained in:
49lf
2024-07-31 14:22:32 -04:00
parent 4afbb1eae7
commit 4c2b807890
6 changed files with 54 additions and 14 deletions

View File

@ -45,6 +45,7 @@
"html2canvas-pro": "^1.5.5", "html2canvas-pro": "^1.5.5",
"json-rpc-2.0": "^1.6.0", "json-rpc-2.0": "^1.6.0",
"jszip": "^3.10.1", "jszip": "^3.10.1",
"openid-client": "^5.6.5",
"re-resizable": "^6.9.11", "re-resizable": "^6.9.11",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@ -149,6 +150,8 @@
"@types/wait-on": "^5.3.4", "@types/wait-on": "^5.3.4",
"@types/wicg-file-system-access": "^2023.10.5", "@types/wicg-file-system-access": "^2023.10.5",
"@types/ws": "^8.5.10", "@types/ws": "^8.5.10",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"@vitejs/plugin-react": "^4.3.0", "@vitejs/plugin-react": "^4.3.0",
"@vitest/web-worker": "^1.5.0", "@vitest/web-worker": "^1.5.0",
"@wdio/cli": "^8.24.3", "@wdio/cli": "^8.24.3",
@ -177,8 +180,6 @@
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"ts-node": "^10.0.0", "ts-node": "^10.0.0",
"typescript": "^4.5.4", "typescript": "^4.5.4",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"vite": "^5.0.12", "vite": "^5.0.12",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
"vite-plugin-package-version": "^1.1.0", "vite-plugin-package-version": "^1.1.0",

View File

@ -415,10 +415,6 @@ export const setState = async (
appStateStore = state appStateStore = state
} }
export const login = () => {
console.log('STUB')
}
export const getUser = async ( export const getUser = async (
token: string, token: string,
hostname: string hostname: string

View File

@ -5,6 +5,7 @@ import packageJson from '../../package.json'
const open = (args: any) => ipcRenderer.invoke('dialog', args) const open = (args: any) => ipcRenderer.invoke('dialog', args)
const showInFolder = (path: string) => ipcRenderer.invoke('shell.showItemInFolder', path) 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 readFile = (path: string) => fs.readFile(path, 'utf-8')
const rename = (prev: string, next: string) => fs.rename(prev, next) const rename = (prev: string, next: string) => fs.rename(prev, next)
@ -31,6 +32,7 @@ const exposeProcessEnv = (varName: string) => {
import('@kittycad/lib').then((kittycad) => { import('@kittycad/lib').then((kittycad) => {
contextBridge.exposeInMainWorld('electron', { contextBridge.exposeInMainWorld('electron', {
login,
// Passing fs directly is not recommended since it gives a lot of power // Passing fs directly is not recommended since it gives a lot of power
// to the browser side / potential malicious code. We restrict what is // to the browser side / potential malicious code. We restrict what is
// exported. // exported.

View File

@ -146,10 +146,7 @@ async function getUser(context: UserContext) {
}) })
.then((res) => res.json()) .then((res) => res.json())
.catch((err) => console.error('error from Browser getUser', err)) .catch((err) => console.error('error from Browser getUser', err))
: getUserDesktop( : getUserDesktop(context.token, VITE_KC_API_BASE_URL )
'f8864550-84a6-4a06-8d3f-68d29bbe5608' /* context.token */,
VITE_KC_API_BASE_URL
)
const user = await userPromise const user = await userPromise

View File

@ -4,6 +4,7 @@
import { Configuration } from 'wasm-lib/kcl/bindings/Configuration' import { Configuration } from 'wasm-lib/kcl/bindings/Configuration'
import { app, BrowserWindow, ipcMain, dialog, shell } from 'electron' import { app, BrowserWindow, ipcMain, dialog, shell } from 'electron'
import path from 'path' import path from 'path'
import { Issuer } from 'openid-client'
// Handle creating/removing shortcuts on Windows when installing/uninstalling. // Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) { if (require('electron-squirrel-startup')) {
@ -61,3 +62,47 @@ ipcMain.handle('dialog', (event, data) => {
ipcMain.handle('shell.showItemInFolder', (event, data) => { ipcMain.handle('shell.showItemInFolder', (event, data) => {
return shell.showItemInFolder(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
})

View File

@ -5,7 +5,6 @@ import { Themes, getSystemTheme } from '../lib/theme'
import { paths } from 'lib/paths' import { paths } from 'lib/paths'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { APP_NAME } from 'lib/constants' import { APP_NAME } from 'lib/constants'
import { login } from 'lib/desktop'
const SignIn = () => { const SignIn = () => {
const { const {
@ -25,10 +24,10 @@ const SignIn = () => {
? '-dark' ? '-dark'
: '' : ''
const signInTauri = async () => { const signInDesktop = async () => {
// We want to invoke our command to login via device auth. // We want to invoke our command to login via device auth.
try { 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 }) send({ type: 'Log in', token })
} catch (error) { } catch (error) {
console.error('Error with login button', error) console.error('Error with login button', error)
@ -64,7 +63,7 @@ const SignIn = () => {
{isDesktop() ? ( {isDesktop() ? (
<ActionButton <ActionButton
Element="button" Element="button"
onClick={signInTauri} onClick={signInDesktop}
iconStart={{ icon: 'arrowRight' }} iconStart={{ icon: 'arrowRight' }}
className="w-fit mt-4" className="w-fit mt-4"
data-testid="sign-in-button" data-testid="sign-in-button"