-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/authentication #173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
b57e8d9
9e34e10
101cdba
baee54b
dfa54aa
feb393c
5ff0b23
eccbe51
55967b7
c884ee3
2b82f31
89eb6b1
d34820e
98cf574
be0f86f
1d70844
c84ca83
d8ab06b
3120f44
f3a662e
91e5d5e
380a7df
b6faf5d
2753380
0356fef
4cb9b3b
8fd419e
7ada032
1f7558b
e3dc677
3575248
1322cc8
a68ee5d
37b529e
d8d3f3b
e5db2d0
cb12716
fea88a0
ee954b4
b29c230
28bb8d0
dc487ca
a0ecad0
29c96c8
0e8430b
ae0286f
f079aab
0aeb7c3
ea38c39
737596f
78bf8d2
d56dbec
fd907b6
9ca5901
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import logo from './logo.svg'; | ||
| import { icons } from './icons'; | ||
| import rosettaIcon from './icon.png'; | ||
|
|
||
| export { logo, icons }; | ||
| export { logo, icons, rosettaIcon }; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| import { ipcMain } from 'electron'; | ||
| import { RosettaCloudService } from '../services'; | ||
| import { CloudDeploymentPayload } from '../../types/backend'; | ||
|
|
||
| const registerRosettaCloudIpcHandlers = () => { | ||
| ipcMain.handle( | ||
| 'rosettaCloud:push', | ||
| async (_event, body: CloudDeploymentPayload) => { | ||
| return RosettaCloudService.pushProjectToCloud(body); | ||
| }, | ||
| ); | ||
|
|
||
| ipcMain.handle('rosettaCloud:getProfile', async () => { | ||
| return RosettaCloudService.getProfile(); | ||
| }); | ||
|
|
||
| ipcMain.handle('rosettaCloud:refreshProfile', async () => { | ||
| return RosettaCloudService.refreshProfile(); | ||
| }); | ||
|
|
||
| ipcMain.handle('rosettaCloud:getCachedProfile', async () => { | ||
| return RosettaCloudService.getCachedProfile(); | ||
| }); | ||
|
|
||
| ipcMain.handle('rosettaCloud:login', async () => { | ||
| return RosettaCloudService.openLogin(); | ||
| }); | ||
|
|
||
| ipcMain.handle('rosettaCloud:getApiKey', async () => { | ||
| return RosettaCloudService.getApiKey(); | ||
| }); | ||
|
|
||
| ipcMain.handle('rosettaCloud:logout', async () => { | ||
| await RosettaCloudService.clearApiKey(); | ||
| }); | ||
|
|
||
| ipcMain.handle('rosettaCloud:storeApiKey', async (_event, apiKey: string) => { | ||
| await RosettaCloudService.storeApiKey(apiKey); | ||
| }); | ||
|
|
||
| ipcMain.handle( | ||
| 'rosettaCloud:validateApiKey', | ||
| async (_event, apiKey: string) => { | ||
| return RosettaCloudService.validateApiKey(apiKey); | ||
| }, | ||
| ); | ||
|
|
||
| ipcMain.handle( | ||
| 'rosettaCloud:getSecrets', | ||
| async (_event, projectId: string) => { | ||
| return RosettaCloudService.getSecrets(projectId); | ||
| }, | ||
| ); | ||
|
|
||
| ipcMain.handle( | ||
| 'rosettaCloud:deleteSecret', | ||
| async (_event, projectId: string, secretId: string) => { | ||
| return RosettaCloudService.deleteSecret(projectId, secretId); | ||
| }, | ||
| ); | ||
| }; | ||
|
|
||
| export default registerRosettaCloudIpcHandlers; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ import { | |
| SettingsService, | ||
| AnalyticsService, | ||
| UpdateService, | ||
| RosettaCloudService, | ||
| DuckLakeConnectionManager, | ||
| } from './services'; | ||
| import { copyAssetsToUserData } from './utils/fileHelper'; | ||
|
|
@@ -31,13 +32,85 @@ protocol.registerSchemesAsPrivileged([ | |
| bypassCSP: true, | ||
| }, | ||
| }, | ||
| { | ||
| scheme: 'rosetta', | ||
| privileges: { | ||
| standard: true, | ||
| secure: true, | ||
| }, | ||
| }, | ||
| ]); | ||
|
|
||
| setupApplicationIcon(); | ||
|
|
||
| let windowManager: WindowManager | null = null; | ||
| async function handleDeepLink(url: string) { | ||
| try { | ||
| const parsedUrl = new URL(url); | ||
| if ( | ||
| parsedUrl.protocol === 'rosetta:' && | ||
| (parsedUrl.pathname === '//auth' || parsedUrl.host === 'auth') | ||
| ) { | ||
| const apiKey = parsedUrl.searchParams.get('token'); // Still called 'token' in URL for compatibility | ||
| if (apiKey) { | ||
| try { | ||
| await RosettaCloudService.storeApiKey(apiKey); | ||
|
|
||
| windowManager | ||
| ?.getMainWindow() | ||
| ?.webContents.send('rosettaCloud:apiKeyUpdated'); | ||
|
|
||
| windowManager | ||
| ?.getMainWindow() | ||
| ?.webContents.send('rosettaCloud:authSuccess', { | ||
| apiKey, | ||
| }); | ||
|
|
||
| return; | ||
| } catch (storageError) { | ||
| console.error( | ||
| 'Failed to store API key from deep link:', | ||
| storageError, | ||
| ); | ||
| windowManager | ||
| ?.getMainWindow() | ||
| ?.webContents.send('rosettaCloud:authError', { | ||
| error: 'Failed to store API key. Please try again.', | ||
| }); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| windowManager | ||
| ?.getMainWindow() | ||
| ?.webContents.send('rosettaCloud:authError', { | ||
| error: 'Missing API key in deep link response.', | ||
| }); | ||
| } | ||
| } catch (error) { | ||
| console.error('Deep link processing error:', error); | ||
| windowManager?.getMainWindow()?.webContents.send('rosettaCloud:authError', { | ||
| error: | ||
| error instanceof Error | ||
| ? `Failed to process deep link: ${error.message}` | ||
| : 'Failed to process deep link.', | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| // Ensure single instance of the app | ||
| const gotTheLock = app.requestSingleInstanceLock(); | ||
| let windowManager: WindowManager | null = null; | ||
|
|
||
| // Register custom protocol for deep linking | ||
| if (process.defaultApp) { | ||
| if (process.argv.length >= 2) { | ||
| app.setAsDefaultProtocolClient('rosetta', process.execPath, [ | ||
| process.argv[1], | ||
| ]); | ||
| } | ||
| } else { | ||
| app.setAsDefaultProtocolClient('rosetta'); | ||
| } | ||
|
|
||
| if (!gotTheLock) { | ||
| console.log('Another instance is already running. Quitting...'); | ||
|
|
@@ -150,9 +223,15 @@ if (!gotTheLock) { | |
| }) | ||
| .catch(console.log); | ||
|
|
||
| app.on('second-instance', () => { | ||
| app.on('second-instance', (event, commandLine) => { | ||
| if (!windowManager) return; | ||
|
|
||
| // Handle deep link from second instance | ||
| const url = commandLine.find((arg) => arg.startsWith('rosetta://')); | ||
| if (url) { | ||
| handleDeepLink(url); | ||
| } | ||
|
|
||
| const activeWindow = windowManager.getMainWindow(); | ||
|
|
||
| if (activeWindow) { | ||
|
|
@@ -163,6 +242,21 @@ if (!gotTheLock) { | |
| windowManager.startApplication(); | ||
| } | ||
| }); | ||
|
|
||
| // Handle deep links on macOS | ||
| app.on('open-url', (event, url) => { | ||
| event.preventDefault(); | ||
| handleDeepLink(url); | ||
| }); | ||
|
|
||
| // Handle deep links on Windows/Linux | ||
| app.on('ready', () => { | ||
| // Check if app was opened with a deep link | ||
| const url = process.argv.find((arg) => arg.startsWith('rosetta://')); | ||
| if (url) { | ||
| handleDeepLink(url); | ||
| } | ||
| }); | ||
|
Comment on lines
+252
to
+259
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deep links on cold start may be silently lost. When the app is launched via a deep link on Windows/Linux, this Consider deferring deep link handling until the main window is ready, or queuing the URL for later processing. 🔎 Proposed approach+let pendingDeepLinkUrl: string | null = null;
+
async function handleDeepLink(url: string) {
+ // If main window not ready, queue the URL
+ if (!windowManager?.getMainWindow()) {
+ pendingDeepLinkUrl = url;
+ return;
+ }
try {
// ... existing logic
}
}
// In the splash.webContents.once('did-finish-load') callback, after showMainWindow():
+if (pendingDeepLinkUrl) {
+ handleDeepLink(pendingDeepLinkUrl);
+ pendingDeepLinkUrl = null;
+}
|
||
| } | ||
|
|
||
| ipcMain.handle('windows:closeSetup', () => { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove feature branch from publish triggers before merging.
Adding a feature branch to the publish workflow will create draft releases from unfinished code. This appears to be a temporary addition for testing purposes. Ensure this line is removed before merging to
devto avoid:🤖 Prompt for AI Agents