Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down
Original file line number Diff line number Diff line change
@@ -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 (
<AppSessionProvider>
<SessionProvider>
<TitleProvider>
<ModalProvider>
<Outlet />
</ModalProvider>
</TitleProvider>
</AppSessionProvider>
</SessionProvider>
);
};
Original file line number Diff line number Diff line change
@@ -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 (
<MainLayoutComponent
children={children}
headerChildren={<HeaderComponent />}
headerChildren={account !== undefined ? <HeaderComponent /> : null}
/>
);
};
2 changes: 1 addition & 1 deletion app/client/src/shared/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from "./useTitle";
export * from "./useApi";
export * from "./useAppSession";
export * from "./useSession";
export * from "./useCookies";
1 change: 0 additions & 1 deletion app/client/src/shared/hooks/useAppSession.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ export const AppSessionProvider: React.FunctionComponent<ProviderProps> = ({
}, []);

const logout = useCallback(() => {
console.log(account);
if (!account) return;

remove("account-id");
Expand Down
110 changes: 110 additions & 0 deletions app/client/src/shared/hooks/useSession.tsx
Original file line number Diff line number Diff line change
@@ -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<string, string>;
account: Account | null | undefined;
login: () => Promise<void>;
logout: () => void;
};

const SessionContext = React.createContext<SessionState>(undefined);

type ProviderProps = {
children: ReactNode;
};

export const SessionProvider: React.FunctionComponent<ProviderProps> = ({
children,
}) => {
const { get, set, remove } = useCookies();
const { fetch } = useApi();

const [account, setAccount] = useState<Account | null | undefined>(undefined);
const redirectRef = useRef<string>(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 (
<SessionContext.Provider
value={{
account,
login,
logout,
}}
children={children}
/>
);
};

export const useSession = (): SessionState => useContext(SessionContext);
7 changes: 3 additions & 4 deletions app/server/src/modules/api/auth/main.ts
Original file line number Diff line number Diff line change
@@ -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",
});
26 changes: 0 additions & 26 deletions app/server/src/modules/api/auth/redirect.request.ts

This file was deleted.

2 changes: 2 additions & 0 deletions app/server/src/modules/api/auth/request.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#
GET http://localhost:2025/api/auth/request
37 changes: 37 additions & 0 deletions app/server/src/modules/api/auth/request.request.ts
Original file line number Diff line number Diff line change
@@ -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 },
);
},
};
34 changes: 19 additions & 15 deletions app/server/src/modules/api/auth/user.request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
);
},
};
4 changes: 2 additions & 2 deletions app/server/src/shared/consts/config.consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const CONFIG_DEFAULT: ConfigTypes = {
},
auth: {
enabled: false,
appToken: "",
url: "http://localhost:2024",
licenseToken: "",
api: "http://localhost:2024",
},
};
4 changes: 2 additions & 2 deletions app/server/src/shared/types/config.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type ConfigTypes = {
};
auth: {
enabled: boolean;
appToken: string;
url: string;
licenseToken: string;
api: string;
};
};
16 changes: 13 additions & 3 deletions app/server/src/system/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,26 @@ export const api = () => {
kind: RequestKind | RequestKind[];
}): Promise<boolean> => {
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;

switch (kind) {
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;
Expand Down
Loading