Files
egbim_qa_platform/apps/web/src/server/support-auth.ts
T
root aaddfc7bfc
Deploy feedback demo / deploy (push) Failing after 4m26s
API 적용 최초 배포
2026-09-01 17:12:46 +09:00

110 lines
2.9 KiB
TypeScript

/**
* Copyright 2025 LY Corporation
*
* LY Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
import type { NextApiRequest } from 'next';
import { supportExternalUrl } from './support-external';
type StoredJwt = { accessToken?: string };
export interface SupportPrincipal {
user_id: string;
tenant_id: string;
email?: string | null;
name?: string | null;
department?: string | null;
phone_number?: string | null;
is_admin?: boolean;
is_system_admin?: boolean;
roles?: string[];
}
const SUPPORT_MANAGER_ROLES = new Set([
'SYSTEM_ADMIN',
'SUPER_ADMIN',
'PROJECT_MANAGER',
]);
export const isSupportAdmin = (principal: SupportPrincipal) =>
principal.is_admin === true ||
principal.is_system_admin === true ||
(Array.isArray(principal.roles) &&
principal.roles.some((role) => SUPPORT_MANAGER_ROLES.has(role)));
export const applySupportCommentPermissions = <
T extends {
author_id: string;
author_tenant_id: string;
},
>(comment: T, principal: SupportPrincipal) => {
const isAuthor =
comment.author_id === principal.user_id &&
comment.author_tenant_id === principal.tenant_id;
const canManage = isSupportAdmin(principal);
return {
...comment,
can_edit: canManage || isAuthor,
can_delete: canManage || isAuthor,
};
};
export const getSupportAuthHeaders = (
req: NextApiRequest,
): Record<string, string> => {
const authorization = req.headers.authorization;
if (authorization) return { Authorization: authorization };
const rawCookie = req.cookies.jwt;
if (!rawCookie) return {};
try {
const parsed = JSON.parse(decodeURIComponent(rawCookie)) as StoredJwt;
return parsed.accessToken ?
{ Authorization: 'Bearer ' + parsed.accessToken }
: {};
} catch {
return {};
}
};
export const getSupportPrincipal = async (
req: NextApiRequest,
): Promise<SupportPrincipal | null> => {
const headers = getSupportAuthHeaders(req);
if (!headers.Authorization) return null;
try {
const response = await fetch(supportExternalUrl('/access'), {
headers,
});
if (!response.ok) return null;
const data = (await response.json()) as Partial<SupportPrincipal>;
if (
typeof data.user_id !== 'string' ||
typeof data.tenant_id !== 'string' ||
!data.user_id ||
!data.tenant_id
) {
return null;
}
return data as SupportPrincipal;
} catch {
return null;
}
};