mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 07:05:24 +00:00
feat: let the login page send the token back to the mobile app
This commit is contained in:
1 parent
73c15f7c58
commit
3d92725ce6
8 files changed
+242
-23
No files matched your search
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Sign in for the Termix mobile app in a real browser. The app opens the
|
||||
* login page with ?return_to=termix-mobile://..., and after any login method
|
||||
* the page sends the token back to that address. Only the app's own scheme
|
||||
* is accepted, so the value can never send a token to a website.
|
||||
*/
|
||||
|
||||
const STORAGE_KEY = "termix-app-return";
|
||||
const PARAM = "return_to";
|
||||
const APP_RETURN = /^termix-mobile:\/\/[A-Za-z0-9._~/-]*$/;
|
||||
|
||||
export function isAppReturn(value: unknown): value is string {
|
||||
return typeof value === "string" && APP_RETURN.test(value);
|
||||
}
|
||||
|
||||
/** Reads return_to from the address bar once and keeps it for this tab. */
|
||||
export function captureAppReturn(): string | null {
|
||||
try {
|
||||
const url = new URL(window.location.href);
|
||||
const value = url.searchParams.get(PARAM);
|
||||
if (value !== null) {
|
||||
url.searchParams.delete(PARAM);
|
||||
window.history.replaceState({}, document.title, url.toString());
|
||||
if (isAppReturn(value)) sessionStorage.setItem(STORAGE_KEY, value);
|
||||
else sessionStorage.removeItem(STORAGE_KEY);
|
||||
}
|
||||
return pendingAppReturn();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function pendingAppReturn(): string | null {
|
||||
try {
|
||||
const value = sessionStorage.getItem(STORAGE_KEY);
|
||||
return isAppReturn(value) ? value : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function appReturnUrl(
|
||||
base: string,
|
||||
params: Record<string, string>,
|
||||
): string {
|
||||
const query = new URLSearchParams(params).toString();
|
||||
return query ? `${base}?${query}` : base;
|
||||
}
|
||||
|
||||
/** Sends the result to the app. False when no app asked for it. */
|
||||
export function handOffToApp(params: Record<string, string>): boolean {
|
||||
const base = pendingAppReturn();
|
||||
if (!base) return false;
|
||||
try {
|
||||
sessionStorage.removeItem(STORAGE_KEY);
|
||||
} catch {
|
||||
// The redirect still goes out.
|
||||
}
|
||||
window.location.replace(appReturnUrl(base, params));
|
||||
return true;
|
||||
}
|
||||
Reference in new issue
Block a user