diff --git a/app/client/src/modules/account/components/header/header.component.tsx b/app/client/src/modules/account/components/header/header.component.tsx
index 489ce23..86eef96 100644
--- a/app/client/src/modules/account/components/header/header.component.tsx
+++ b/app/client/src/modules/account/components/header/header.component.tsx
@@ -1,12 +1,10 @@
import React from "react";
-import { useAppSession } from "shared/hooks";
import { ButtonComponent } from "@openhotel/web-components";
import styles from "./header.module.scss";
+import { useSession } from "shared/hooks";
export const HeaderComponent: React.FC = () => {
- const { account, login, logout } = useAppSession();
-
- if (account === undefined) return;
+ const { login, logout, account } = useSession();
if (!account)
return (
diff --git a/app/client/src/modules/application/components/providers/providers.component.tsx b/app/client/src/modules/application/components/providers/providers.component.tsx
index c2ab40b..2720ffc 100644
--- a/app/client/src/modules/application/components/providers/providers.component.tsx
+++ b/app/client/src/modules/application/components/providers/providers.component.tsx
@@ -1,16 +1,17 @@
import { Outlet } from "react-router";
-import { TitleProvider, AppSessionProvider } from "shared/hooks";
+import { TitleProvider } from "shared/hooks";
import React from "react";
import { ModalProvider } from "@openhotel/web-components";
+import { SessionProvider } from "shared/hooks";
export const ProvidersComponent = () => {
return (
-
+
-
+
);
};
diff --git a/app/client/src/modules/application/components/wrapper-layout/wrapper-layout.component.tsx b/app/client/src/modules/application/components/wrapper-layout/wrapper-layout.component.tsx
index 4db7b2b..e4af00d 100644
--- a/app/client/src/modules/application/components/wrapper-layout/wrapper-layout.component.tsx
+++ b/app/client/src/modules/application/components/wrapper-layout/wrapper-layout.component.tsx
@@ -1,16 +1,18 @@
import React from "react";
import { MainLayoutComponent } from "@openhotel/web-components";
import { HeaderComponent } from "modules/account";
+import { useSession } from "shared/hooks";
type Props = {
children: React.ReactNode;
};
export const WrapperLayoutComponent = ({ children }: Props) => {
+ const { account } = useSession();
return (
}
+ headerChildren={account !== undefined ? : null}
/>
);
};
diff --git a/app/client/src/shared/hooks/index.ts b/app/client/src/shared/hooks/index.ts
index afd4144..cecf1b5 100644
--- a/app/client/src/shared/hooks/index.ts
+++ b/app/client/src/shared/hooks/index.ts
@@ -1,4 +1,4 @@
export * from "./useTitle";
export * from "./useApi";
-export * from "./useAppSession";
+export * from "./useSession";
export * from "./useCookies";
diff --git a/app/client/src/shared/hooks/useAppSession.tsx b/app/client/src/shared/hooks/useAppSession.tsx
index 8c0f547..1c650db 100644
--- a/app/client/src/shared/hooks/useAppSession.tsx
+++ b/app/client/src/shared/hooks/useAppSession.tsx
@@ -100,7 +100,6 @@ export const AppSessionProvider: React.FunctionComponent = ({
}, []);
const logout = useCallback(() => {
- console.log(account);
if (!account) return;
remove("account-id");
diff --git a/app/client/src/shared/hooks/useSession.tsx b/app/client/src/shared/hooks/useSession.tsx
new file mode 100644
index 0000000..9da7702
--- /dev/null
+++ b/app/client/src/shared/hooks/useSession.tsx
@@ -0,0 +1,110 @@
+import React, {
+ ReactNode,
+ useCallback,
+ useContext,
+ useEffect,
+ useRef,
+ useState,
+} from "react";
+import { useApi, useCookies } from "shared/hooks";
+import { Account } from "shared/types";
+
+type SessionState = {
+ // getHeaders: () => Record;
+ account: Account | null | undefined;
+ login: () => Promise;
+ logout: () => void;
+};
+
+const SessionContext = React.createContext(undefined);
+
+type ProviderProps = {
+ children: ReactNode;
+};
+
+export const SessionProvider: React.FunctionComponent = ({
+ children,
+}) => {
+ const { get, set, remove } = useCookies();
+ const { fetch } = useApi();
+
+ const [account, setAccount] = useState(undefined);
+ const redirectRef = useRef(null);
+
+ const params = new URLSearchParams(window.location.search);
+ // const $state = params.get("state");
+ const $token = params.get("token");
+
+ const makeRequest = useCallback(async () => {
+ if (redirectRef.current) return;
+
+ const { status, data } = await fetch({
+ pathname: "auth/request",
+ preventReload: true,
+ });
+
+ switch (status) {
+ // auth disabled
+ case 410:
+ setAccount(null);
+ break;
+ case 200:
+ setAccount(null);
+ redirectRef.current = data.redirectUrl;
+ break;
+ }
+ }, []);
+
+ useEffect(() => {
+ const token = $token ?? get("connection-token");
+ if (token) set("connection-token", token, 1);
+
+ if (window.location.search)
+ window.history.replaceState("", document.title, window.location.pathname);
+
+ (async () => {
+ if (token) {
+ try {
+ const { status, data } = await fetch({
+ pathname: "auth/user",
+ headers: {
+ token,
+ },
+ preventReload: true,
+ });
+ setAccount(data);
+ return;
+ } catch (e) {
+ remove("connection-token");
+ }
+ }
+
+ await makeRequest();
+ })();
+ }, []);
+
+ const login = useCallback(async () => {
+ await makeRequest();
+ window.location.replace(redirectRef.current);
+ }, [fetch]);
+
+ const logout = useCallback(async () => {
+ if (!account) return;
+
+ remove("connection-token");
+ setAccount(null);
+ }, [account, fetch]);
+
+ return (
+
+ );
+};
+
+export const useSession = (): SessionState => useContext(SessionContext);
diff --git a/app/server/src/modules/api/auth/main.ts b/app/server/src/modules/api/auth/main.ts
index dc21f76..7ec4d1d 100644
--- a/app/server/src/modules/api/auth/main.ts
+++ b/app/server/src/modules/api/auth/main.ts
@@ -1,10 +1,9 @@
import { RequestType, getPathRequestList } from "@oh/utils";
-import { redirectRequest } from "./redirect.request.ts";
-import { userRequest } from "./user.request.ts";
-import { getRequest } from "./main.request.ts";
+import { requestRequest } from "modules/api/auth/request.request.ts";
+import { userRequest } from "modules/api/auth/user.request.ts";
export const authList: RequestType[] = getPathRequestList({
- requestList: [getRequest, redirectRequest, userRequest],
+ requestList: [requestRequest, userRequest],
pathname: "/auth",
});
diff --git a/app/server/src/modules/api/auth/redirect.request.ts b/app/server/src/modules/api/auth/redirect.request.ts
deleted file mode 100644
index ef0dd8d..0000000
--- a/app/server/src/modules/api/auth/redirect.request.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { RequestType, RequestMethod } from "@oh/utils";
-import { System } from "system/main.ts";
-import { getTokenData } from "@oh/utils";
-
-export const redirectRequest: RequestType = {
- method: RequestMethod.GET,
- pathname: "/redirect",
- func: (request) => {
- const {
- auth: { url: authUrl, appToken },
- } = System.getConfig();
- const { id } = getTokenData(appToken);
-
- const $url = new URL(authUrl + "/apps");
- $url.searchParams.append("appId", id);
- return Response.json(
- {
- status: 200,
- data: {
- url: $url,
- },
- },
- { status: 200 },
- );
- },
-};
diff --git a/app/server/src/modules/api/auth/request.http b/app/server/src/modules/api/auth/request.http
new file mode 100644
index 0000000..a58a758
--- /dev/null
+++ b/app/server/src/modules/api/auth/request.http
@@ -0,0 +1,2 @@
+#
+GET http://localhost:2025/api/auth/request
diff --git a/app/server/src/modules/api/auth/request.request.ts b/app/server/src/modules/api/auth/request.request.ts
new file mode 100644
index 0000000..bdc74bb
--- /dev/null
+++ b/app/server/src/modules/api/auth/request.request.ts
@@ -0,0 +1,37 @@
+import {
+ RequestType,
+ RequestMethod,
+ getResponse,
+ HttpStatusCode,
+} from "@oh/utils";
+import { System } from "system/main.ts";
+
+export const requestRequest: RequestType = {
+ method: RequestMethod.GET,
+ pathname: "/request",
+ func: (request) => {
+ const config = System.getConfig();
+
+ if (!config.auth.enabled) return getResponse(HttpStatusCode.GONE);
+
+ const hotelId = System.auth.getHotelId();
+ const integrationId = System.auth.getIntegrationId();
+
+ const composedRedirectUrl = new URL(`${config.auth.api}/connection`);
+ composedRedirectUrl.searchParams.append("state", "test");
+
+ if (hotelId) composedRedirectUrl.searchParams.append("hotelId", hotelId);
+ if (integrationId)
+ composedRedirectUrl.searchParams.append("integrationId", integrationId);
+
+ return Response.json(
+ {
+ status: 200,
+ data: {
+ redirectUrl: composedRedirectUrl.href,
+ },
+ },
+ { status: 200 },
+ );
+ },
+};
diff --git a/app/server/src/modules/api/auth/user.request.ts b/app/server/src/modules/api/auth/user.request.ts
index e4294bf..dbffbcc 100644
--- a/app/server/src/modules/api/auth/user.request.ts
+++ b/app/server/src/modules/api/auth/user.request.ts
@@ -6,22 +6,26 @@ export const userRequest: RequestType = {
pathname: "/user",
kind: RequestKind.ACCOUNT,
func: async (request: Request) => {
- const accountId = request.headers.get("account-id");
- const accountToken = request.headers.get("account-token");
- const {
- auth: { url: authUrl, appToken },
- } = System.getConfig();
+ const connectionToken = request.headers.get("token");
- const data = await fetch(`${authUrl}/api/v3/user/@me`, {
- headers: {
- "app-token": appToken,
- "account-id": accountId,
- "account-token": accountToken,
- },
- }).then((response) => response.json());
-
- return Response.json(data, {
- status: data.status,
+ const { accountId, username, admin, languages } = await System.auth.fetch({
+ url: "/user/@me",
+ connectionToken,
});
+
+ return Response.json(
+ {
+ status: 200,
+ data: {
+ accountId,
+ username,
+ admin,
+ languages,
+ },
+ },
+ {
+ status: 200,
+ },
+ );
},
};
diff --git a/app/server/src/shared/consts/config.consts.ts b/app/server/src/shared/consts/config.consts.ts
index 4b902a7..38f6cd2 100644
--- a/app/server/src/shared/consts/config.consts.ts
+++ b/app/server/src/shared/consts/config.consts.ts
@@ -23,7 +23,7 @@ export const CONFIG_DEFAULT: ConfigTypes = {
},
auth: {
enabled: false,
- appToken: "",
- url: "http://localhost:2024",
+ licenseToken: "",
+ api: "http://localhost:2024",
},
};
diff --git a/app/server/src/shared/types/config.types.ts b/app/server/src/shared/types/config.types.ts
index 316cfcf..6f3875c 100644
--- a/app/server/src/shared/types/config.types.ts
+++ b/app/server/src/shared/types/config.types.ts
@@ -21,7 +21,7 @@ export type ConfigTypes = {
};
auth: {
enabled: boolean;
- appToken: string;
- url: string;
+ licenseToken: string;
+ api: string;
};
};
diff --git a/app/server/src/system/api.ts b/app/server/src/system/api.ts
index 00ad3a0..05e4555 100644
--- a/app/server/src/system/api.ts
+++ b/app/server/src/system/api.ts
@@ -82,8 +82,7 @@ export const api = () => {
kind: RequestKind | RequestKind[];
}): Promise => {
const check = async (kind: RequestKind) => {
- const accountId = request.headers.get("account-id");
- const accountToken = request.headers.get("account-token");
+ const connectionToken = request.headers.get("token");
if (!System.getConfig().auth.enabled) return true;
@@ -91,7 +90,18 @@ export const api = () => {
case RequestKind.PUBLIC:
return true;
case RequestKind.ACCOUNT:
- if (!accountId || !accountToken) return false;
+ if (!connectionToken) return false;
+
+ try {
+ const { accountId } = await System.auth.fetch({
+ url: "/user/@me",
+ connectionToken,
+ });
+ return Boolean(accountId);
+ } catch (e) {
+ return false;
+ }
+
return true;
default:
return false;
diff --git a/app/server/src/system/auth.ts b/app/server/src/system/auth.ts
new file mode 100644
index 0000000..7a5ac54
--- /dev/null
+++ b/app/server/src/system/auth.ts
@@ -0,0 +1,69 @@
+import { ConfigTypes } from "shared/types/config.types.ts";
+
+type Props = {
+ url: string;
+ connectionToken?: string;
+};
+
+export const auth = () => {
+ let $config: ConfigTypes;
+
+ let $hotelId: string;
+ let $integrationId: string;
+ //TODO permanent op
+ let $ownerId: string;
+
+ const load = async (config: ConfigTypes) => {
+ $config = config;
+ if (!(await isAuthEnabled()))
+ console.error("/!\\ Auth service is down or Hotel License is not valid!");
+ };
+
+ const isAuthEnabled = async () => {
+ if (!$config.auth.enabled) return true;
+
+ try {
+ const { hotelId, accountId, integrationId } = await $fetch({
+ url: "/hotel/license",
+ });
+ $hotelId = hotelId;
+ $integrationId = integrationId;
+ $ownerId = accountId;
+ return true;
+ } catch (e) {
+ return false;
+ }
+ };
+
+ const $fetch = async ({ url, connectionToken }: Props) => {
+ const { status, data } = await (
+ await fetch(`${$config.auth.api}/api/v3${url}`, {
+ headers: new Headers({
+ "Content-Type": "application/json",
+ "license-token": $config.auth.licenseToken,
+ ...(connectionToken
+ ? {
+ "connection-token": connectionToken,
+ }
+ : {}),
+ }),
+ })
+ ).json();
+ return data;
+ };
+
+ const getHotelId = () => $hotelId;
+ const getIntegrationId = () => $integrationId;
+ const getOwnerId = () => $ownerId;
+
+ return {
+ load,
+ isAuthEnabled,
+
+ fetch: $fetch,
+
+ getHotelId,
+ getIntegrationId,
+ getOwnerId,
+ };
+};
diff --git a/app/server/src/system/main.ts b/app/server/src/system/main.ts
index 4422329..298d0cf 100644
--- a/app/server/src/system/main.ts
+++ b/app/server/src/system/main.ts
@@ -5,6 +5,7 @@ import { CONFIG_DEFAULT } from "shared/consts/config.consts.ts";
import { Migrations } from "./migrations/main.ts";
import { backups } from "./backups.ts";
import { accounts } from "./accounts.ts";
+import { auth } from "system/auth.ts";
export const System = (() => {
let $config: ConfigTypes;
@@ -15,6 +16,7 @@ export const System = (() => {
const $api = api();
const $backups = backups();
const $accounts = accounts();
+ const $auth = auth();
let $db: DbMutable;
const load = async (envs: Envs, testMode: boolean = false) => {
@@ -28,6 +30,8 @@ export const System = (() => {
$isTestMode = testMode;
+ await $auth.load($config);
+
const isProduction = !testMode && $config.version !== "development";
if (
@@ -90,5 +94,6 @@ export const System = (() => {
api: $api,
backups: $backups,
accounts: $accounts,
+ auth: $auth,
};
})();