-
Notifications
You must be signed in to change notification settings - Fork 1
fix: unified session identity across dev/prod for shared Neon DB #99
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -199,20 +199,57 @@ ipcMain.on(IPC.INTER_APP_SEND, (event: IpcMainEvent, msg: InterAppMessage) => { | |
| }); | ||
| }); | ||
|
|
||
| // ---------- OAuth popup handling ---------- | ||
| // Open OAuth flows in an Electron BrowserWindow so the callback stays | ||
| // inside the app. Other popups still open in the system browser. | ||
|
|
||
| const OAUTH_HOSTS = ["accounts.google.com"]; | ||
|
|
||
| function openAuthWindow(url: string) { | ||
| const authWin = new BrowserWindow({ | ||
| width: 500, | ||
| height: 680, | ||
| webPreferences: { | ||
| nodeIntegration: false, | ||
| contextIsolation: true, | ||
| }, | ||
| }); | ||
|
|
||
| authWin.loadURL(url); | ||
|
|
||
| // After the OAuth provider redirects to localhost (the callback), | ||
| // let the request complete then close the popup. | ||
| authWin.webContents.on("did-navigate", (_event, navUrl) => { | ||
| try { | ||
| const parsed = new URL(navUrl); | ||
| if (parsed.hostname === "localhost") { | ||
|
Comment on lines
+220
to
+225
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. 🟡 OAuth popup never auto-closes for hosted production app callbacks
How did I do? React with 👍 or 👎 to help me improve. |
||
| // Give the callback handler time to store tokens then close | ||
| setTimeout(() => { | ||
| if (!authWin.isDestroyed()) authWin.close(); | ||
| }, 1500); | ||
| } | ||
| } catch { | ||
| // ignore | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| // ---------- Webview popup handling ---------- | ||
| // Open popups from webviews (e.g. OAuth flows) in the system browser | ||
| // instead of creating broken Electron popup windows. | ||
|
|
||
| app.on("web-contents-created", (_event, contents) => { | ||
| // Only intercept webview guest contents | ||
| if (contents.getType() !== "webview") return; | ||
|
|
||
| contents.setWindowOpenHandler(({ url }) => { | ||
| // Only allow http/https URLs to prevent protocol-handler attacks | ||
| // (e.g. ms-msdt:, file://, etc.) | ||
| try { | ||
| const parsed = new URL(url); | ||
| if (parsed.protocol === "https:" || parsed.protocol === "http:") { | ||
| if (parsed.protocol !== "https:" && parsed.protocol !== "http:") { | ||
| return { action: "deny" }; | ||
| } | ||
| // OAuth flows stay in Electron so the callback redirect works | ||
| if (OAUTH_HOSTS.includes(parsed.hostname)) { | ||
| openAuthWindow(url); | ||
| } else { | ||
| shell.openExternal(url); | ||
| } | ||
| } catch { | ||
|
|
@@ -245,9 +282,13 @@ app.on("web-contents-created", (_event, contents) => { | |
| return; | ||
| } | ||
|
|
||
| // Forward other Cmd+ shortcuts: T, Shift+T, 1-9, [, ] | ||
| // Forward other Cmd+ shortcuts: R, T, Shift+T, 1-9, [, ] | ||
| const isShortcut = | ||
| key === "t" || key === "[" || key === "]" || (key >= "1" && key <= "9"); | ||
| key === "r" || | ||
| key === "t" || | ||
| key === "[" || | ||
| key === "]" || | ||
| (key >= "1" && key <= "9"); | ||
|
|
||
| if (isShortcut) { | ||
| event.preventDefault(); | ||
|
|
@@ -311,6 +352,16 @@ app.whenReady().then(() => { | |
| return; | ||
| } | ||
|
|
||
| // Cmd+R — refresh active webview, not the shell | ||
| if (key === "r") { | ||
| _event.preventDefault(); | ||
| win.webContents.send("shortcut:keydown", { | ||
| key: "r", | ||
| shiftKey: input.shift, | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| // Cmd+W — close tab instead of window | ||
| if (key === "w") { | ||
| _event.preventDefault(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -101,6 +101,7 @@ export default function App() { | |
| }, [enabledApps.map((a) => a.id).join(",")]); | ||
|
|
||
| const closedTabsRef = useRef<{ tab: Tab; appId: string }[]>([]); | ||
| const [refreshKey, setRefreshKey] = useState(0); | ||
|
|
||
| const currentAppTabs = appTabs[activeSidebarAppId]; | ||
|
|
||
|
|
@@ -196,6 +197,11 @@ export default function App() { | |
| (key: string, shiftKey: boolean) => { | ||
| const k = key.toLowerCase(); | ||
|
|
||
| if (k === "r") { | ||
| setRefreshKey((n) => n + 1); | ||
| return; | ||
| } | ||
|
|
||
| if (k === "t") { | ||
| if (shiftKey) handleReopenTab(); | ||
| else handleNewTab(); | ||
|
|
@@ -314,6 +320,7 @@ export default function App() { | |
| app={appDef} | ||
| appConfig={app} | ||
| isActive={isActive} | ||
| refreshKey={isActive ? refreshKey : 0} | ||
|
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. 🟡 refreshKey resets inactive webviews to 0, causing unintended reload on tab switchInactive How did I do? React with 👍 or 👎 to help me improve. |
||
| /> | ||
| ))} | ||
| </div> | ||
|
|
||
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.
🔴 Production auth broken: ACCESS_TOKEN sessions have null email, causing infinite login loop
The
mountAuthRouteslogin handler callsawait addSession(sessionToken)without an email, storingemail = NULLin the DB.getSessionEmailreturnsnullfor NULL emails (line 135:(rows[0].email as string) ?? null), so this block never returns a session and falls through toreturn null— causing every ACCESS_TOKEN-authenticated request to be treated as unauthenticated. Fix:await addSession(sessionToken, "user")in the login handler to match pre-PR behavior.How did I do? React with 👍 or 👎 to help me improve.