Skip to content

Commit 816ecd1

Browse files
make auth flow possible to complete in dev (#172)
1 parent 7810e14 commit 816ecd1

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ You can then launch a packaged version of the app (needed to test certain featur
3131

3232
To test your changes on other platforms, we recommend using a Virtual Machine host like [UTM](https://mac.getutm.app).
3333

34+
When going through the authentication flow in development (through unpackaged app) on macOS and Linux, after clicking "Login" on the welcome page, a new empty Electron window will open. This is expected, as [deeplinks are not support in unpackaged apps](https://www.electronjs.org/docs/latest/tutorial/launch-app-from-url-in-another-app#:~:text=On%20macOS%20and%20Linux%2C%20this%20feature%20will%20only%20work%20when%20your%20app%20is%20packaged.%20It%20will%20not%20work%20when%20you%27re%20launching%20it%20in%20development%20from%20the%20command%2Dline). To finish the flow, copy the URL from the browser into the clipboard (it should look like `http://localhost:3000/desktopApp/authSuccess?authToken=...`), and from the app menubar choose "File -> Complete Auth From Clipboard". This menu item is only available in dev.
35+
3436
## API Versioning
3537

3638
The Electron app communicates with the web frontend through the `replitDesktop` global object defined in `src/preload.ts`. As we develop both applications, this API has to be able to adapt, but at the same time can't break existing clients. The main failure mode we're trying to avoid is someone opening an older version of the Electron app and loading a newer version of the web client which requires a new API that's not supported by the old Electron client.
@@ -100,3 +102,4 @@ Note that to recreate the `pfx` file (which is what's ultimately needed to sign
100102
### CI
101103

102104
We sign the app in CI as part of the build and release process when publishing a new release. Make sure that the above env vars (`APPLE_*` and `WINDOWS_*`) remain valid credentials and are kept up to date in the repository secrets settings used by GitHub actions otherwise the app will not get correctly signed on subsequent releases.
105+

src/createMenu.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import {
22
app,
3+
clipboard,
4+
dialog,
35
Menu,
46
MenuItem,
57
MenuItemConstructorOptions,
68
} from 'electron';
79
import { isProduction } from './constants';
810
import { createWindow } from './createWindow';
11+
import { handleAuthComplete } from './deeplink';
912
import { isMac } from './platform';
1013

1114
const newWindowMenuItem = {
@@ -14,6 +17,38 @@ const newWindowMenuItem = {
1417
click: () => createWindow(),
1518
};
1619

20+
const completeAuthFromClipboardMenuItem = {
21+
label: 'Complete Auth From Clipboard',
22+
click: () => completeAuthFromClipboard(),
23+
};
24+
25+
// we use deeplinking for authentication, but deeplinks are not supported in
26+
// unpackaged macOS and Linux builds, this is a dev-only workaround to finish
27+
// the authentication flow by copying the auth url into a clipboard
28+
async function completeAuthFromClipboard() {
29+
const maybeUrl = clipboard.readText();
30+
31+
function showUrlInvalidDialog(url: string) {
32+
dialog.showErrorBox(
33+
'Authentication Error',
34+
`The URL in the clipboard is not valid: ${url}`,
35+
);
36+
}
37+
38+
try {
39+
const url = new URL(maybeUrl);
40+
const authToken = url.searchParams.get('authToken');
41+
42+
if (url.pathname === '/desktopApp/authSuccess' && authToken?.length > 0) {
43+
handleAuthComplete(authToken);
44+
} else {
45+
showUrlInvalidDialog(maybeUrl);
46+
}
47+
} catch (e) {
48+
showUrlInvalidDialog(maybeUrl);
49+
}
50+
}
51+
1752
export function createDockMenu(): Menu {
1853
const menu = new Menu();
1954

@@ -50,6 +85,7 @@ export function createApplicationMenu(): Menu {
5085
label: 'File',
5186
submenu: [
5287
newWindowMenuItem,
88+
!isProduction ? completeAuthFromClipboardMenuItem : [],
5389
{ type: 'separator' },
5490
isMac() ? { role: 'close' } : { role: 'quit' },
5591
],
@@ -71,17 +107,16 @@ export function createApplicationMenu(): Menu {
71107
],
72108
});
73109

74-
const devOnlyMenuItems = [
110+
// View Menu
111+
const devOnlyViewMenuItems = [
75112
{ role: 'reload' },
76113
{ role: 'forceReload' },
77114
{ type: 'separator' },
78115
];
79-
80-
// View Menu
81116
template.push({
82117
label: 'View',
83118
submenu: [
84-
...(!isProduction ? devOnlyMenuItems : []),
119+
...(!isProduction ? devOnlyViewMenuItems : []),
85120
...(allowDevtools ? [{ role: 'toggleDevTools' }] : []),
86121
{ role: 'togglefullscreen' },
87122
],

src/deeplink.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ function handleNew(language: string) {
130130

131131
function handleRepl(url: string) {
132132
if (
133-
!personalReplUrlRegex.test(url) &&
134-
!teamReplUrlRegex.test(url) &&
133+
!personalReplUrlRegex.test(url) &&
134+
!teamReplUrlRegex.test(url) &&
135135
!legacyTeamReplUrlRegex.test(url)
136136
) {
137137
log.error('Expected valid workspace URL');
@@ -152,7 +152,7 @@ function handleRepl(url: string) {
152152
});
153153
}
154154

155-
function handleAuthComplete(authToken: string) {
155+
export function handleAuthComplete(authToken: string) {
156156
const windows = BrowserWindow.getAllWindows();
157157
const authUrl = `${baseUrl}${authPage}`;
158158

0 commit comments

Comments
 (0)