mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-01 13:43:25 +00:00
Handle Discord Login in capacitor apps
This commit is contained in:
@@ -592,6 +592,6 @@ export async function buildGameUrl(
|
||||
const config = await getServerConfigFromClient();
|
||||
|
||||
const apiPath = `/api/${path}/${gameID}`;
|
||||
const baseUrl = process.env.API_BASE_URL || "/";
|
||||
return `${baseUrl}${config.workerPath(gameID)}${apiPath}`;
|
||||
const baseUrl = process.env.API_BASE_URL || "";
|
||||
return `${baseUrl}/${config.workerPath(gameID)}${apiPath}`;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators.js";
|
||||
import { translateText } from "../client/Utils";
|
||||
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
|
||||
import { GameInfo, GameRecord } from "../core/Schemas";
|
||||
import { generateID } from "../core/Util";
|
||||
import "./components/baseComponents/Button";
|
||||
@@ -171,7 +172,8 @@ export class JoinPrivateLobbyModal extends LitElement {
|
||||
}
|
||||
|
||||
private async checkActiveLobby(lobbyId: string): Promise<boolean> {
|
||||
const url = await buildGameUrl(lobbyId, "game/exists");
|
||||
const config = await getServerConfigFromClient();
|
||||
const url = `${process.env.API_BASE_URL || ""}/${config.workerPath(lobbyId)}/api/game/${lobbyId}/exists`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
|
||||
+9
-1
@@ -30,7 +30,13 @@ import { NewsButton } from "./components/NewsButton";
|
||||
import "./components/baseComponents/Button";
|
||||
import { OButton } from "./components/baseComponents/Button";
|
||||
import "./components/baseComponents/Modal";
|
||||
import { discordLogin, getUserMe, isLoggedIn, logOut } from "./jwt";
|
||||
import {
|
||||
discordLogin,
|
||||
getUserMe,
|
||||
initializeAuthListener,
|
||||
isLoggedIn,
|
||||
logOut,
|
||||
} from "./jwt";
|
||||
import "./styles.css";
|
||||
|
||||
declare global {
|
||||
@@ -77,6 +83,8 @@ class Client {
|
||||
constructor() {}
|
||||
|
||||
initialize(): void {
|
||||
initializeAuthListener();
|
||||
|
||||
const gameVersion = document.getElementById(
|
||||
"game-version",
|
||||
) as HTMLDivElement;
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Redirecting...</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Please wait while we redirect you back to the application.</p>
|
||||
<script>
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const code = params.get("code");
|
||||
const error = params.get("error");
|
||||
const state = params.get("state");
|
||||
|
||||
if (code) {
|
||||
let url = `com.openfront.app://auth?code=${code}`;
|
||||
if (state) {
|
||||
url += `&state=${state}`;
|
||||
}
|
||||
window.location = url;
|
||||
} else if (error) {
|
||||
let url = `com.openfront.app://auth?error=${error}`;
|
||||
if (state) {
|
||||
url += `&state=${state}`;
|
||||
}
|
||||
window.location = url;
|
||||
} else {
|
||||
document.body.innerText =
|
||||
"No code or error found. You can close this window.";
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+84
-5
@@ -1,3 +1,6 @@
|
||||
import { App } from "@capacitor/app";
|
||||
import { Browser } from "@capacitor/browser";
|
||||
import { Capacitor } from "@capacitor/core";
|
||||
import { decodeJwt } from "jose";
|
||||
import { z } from "zod/v4";
|
||||
import {
|
||||
@@ -8,8 +11,12 @@ import {
|
||||
UserMeResponseSchema,
|
||||
} from "../core/ApiSchemas";
|
||||
|
||||
const isNative = Capacitor.getPlatform() !== "web";
|
||||
|
||||
function getAudience() {
|
||||
const { hostname } = new URL(window.location.href);
|
||||
const hostname =
|
||||
process.env.CAPACITOR_PRODUCTION_HOSTNAME ||
|
||||
new URL(window.location.href).hostname;
|
||||
const domainname = hostname.split(".").slice(-2).join(".");
|
||||
return domainname;
|
||||
}
|
||||
@@ -17,7 +24,10 @@ function getAudience() {
|
||||
function getApiBase() {
|
||||
const domainname = getAudience();
|
||||
return domainname === "localhost"
|
||||
? (localStorage.getItem("apiHost") ?? "http://localhost:8787")
|
||||
? (localStorage.getItem("apiHost") ??
|
||||
(isNative && process.env.API_BASE_URL))
|
||||
? process.env.API_BASE_URL!.replace("9000", "8787")
|
||||
: "http://localhost:8787"
|
||||
: `https://api.${domainname}`;
|
||||
}
|
||||
|
||||
@@ -43,8 +53,22 @@ function getToken(): string | null {
|
||||
return localStorage.getItem("token");
|
||||
}
|
||||
|
||||
export function discordLogin() {
|
||||
window.location.href = `${getApiBase()}/login/discord?redirect_uri=${window.location.href}`;
|
||||
export async function discordLogin() {
|
||||
let redirectUri: string;
|
||||
|
||||
if (isNative) {
|
||||
redirectUri = `${process.env.API_BASE_URL}/discord-redirect.html`;
|
||||
} else {
|
||||
redirectUri = window.location.href.split("#")[0];
|
||||
}
|
||||
|
||||
const url = `${getApiBase()}/login/discord?redirect_uri=${encodeURIComponent(redirectUri)}`;
|
||||
|
||||
if (isNative) {
|
||||
await Browser.open({ url });
|
||||
} else {
|
||||
window.location.href = url;
|
||||
}
|
||||
}
|
||||
|
||||
export async function logOut(allSessions: boolean = false) {
|
||||
@@ -101,7 +125,7 @@ function _isLoggedIn(): IsLoggedInResponse {
|
||||
const payload = decodeJwt(token);
|
||||
const { iss, aud, exp, iat } = payload;
|
||||
|
||||
if (iss !== getApiBase()) {
|
||||
if (iss !== getApiBase() && !isNative) {
|
||||
// JWT was not issued by the correct server
|
||||
console.error(
|
||||
'unexpected "iss" claim value',
|
||||
@@ -158,6 +182,61 @@ function _isLoggedIn(): IsLoggedInResponse {
|
||||
}
|
||||
}
|
||||
|
||||
export function initializeAuthListener() {
|
||||
if (Capacitor.getPlatform() === "web") return;
|
||||
|
||||
App.addListener("appUrlOpen", async (data) => {
|
||||
try {
|
||||
const url = new URL(data.url);
|
||||
const code = url.searchParams.get("code");
|
||||
const state = url.searchParams.get("state");
|
||||
const error = url.searchParams.get("error");
|
||||
|
||||
if (error) {
|
||||
console.error("Error from auth provider:", error);
|
||||
await Browser.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (code && state) {
|
||||
const redirectUri = `${process.env.API_BASE_URL}/discord-redirect.html`;
|
||||
const response = await fetch(`${getApiBase()}/mobile/callback`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
code,
|
||||
state,
|
||||
redirect_uri: redirectUri,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to exchange code for token: ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const { token } = await response.json();
|
||||
|
||||
if (token) {
|
||||
localStorage.setItem("token", token);
|
||||
__isLoggedIn = undefined;
|
||||
await Browser.close();
|
||||
window.location.assign(window.location.origin || "/");
|
||||
} else {
|
||||
console.error("No token found in response");
|
||||
await Browser.close();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error handling appUrlOpen", e);
|
||||
await Browser.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function postRefresh(): Promise<boolean> {
|
||||
try {
|
||||
const token = getToken();
|
||||
|
||||
+19
-9
@@ -6,16 +6,26 @@ import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
const config = getServerConfigFromServer();
|
||||
const origin = config.origin();
|
||||
|
||||
const allowedOrigins = [
|
||||
origin,
|
||||
"capacitor://openfront.io",
|
||||
"https://openfront.io",
|
||||
];
|
||||
const allowedOrigins: string[] = [origin];
|
||||
|
||||
if (config.env() === GameEnv.Dev) {
|
||||
const localIp = getLocalIP();
|
||||
if (localIp) {
|
||||
allowedOrigins.push(`http://${localIp}:9000`);
|
||||
switch (config.env()) {
|
||||
case GameEnv.Prod:
|
||||
allowedOrigins.push("capacitor://openfront.io", "https://openfront.io");
|
||||
break;
|
||||
case GameEnv.Preprod:
|
||||
allowedOrigins.push("capacitor://openfront.dev", "https://openfront.dev");
|
||||
break;
|
||||
case GameEnv.Dev: {
|
||||
allowedOrigins.push(
|
||||
"capacitor://localhost",
|
||||
"http://localhost",
|
||||
"http://localhost:8787",
|
||||
);
|
||||
const localIp = getLocalIP();
|
||||
if (localIp) {
|
||||
allowedOrigins.push(`http://${localIp}:9000`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user