feat: enhance CORS handling with public API support and session management
This commit is contained in:
+14
-13
@@ -1,13 +1,12 @@
|
||||
import 'dotenv/config';
|
||||
|
||||
import { API_SERVER_URL } from '@api/constants';
|
||||
import { resolveTrustedBrowserOriginForCors } from '@api/utils/origins';
|
||||
|
||||
import { Hono } from '@api/utils/hono';
|
||||
import { accountRouter } from '@api/routes/account';
|
||||
import { auth } from '@cio/db/auth';
|
||||
import { communityRouter } from '@api/routes/community';
|
||||
import { cors } from 'hono/cors';
|
||||
import { isPublicApiPath, sessionCors } from '@api/middlewares/cors';
|
||||
import { courseRouter } from '@api/routes/course';
|
||||
import { dashAnalyticsRouter } from '@api/routes/dash';
|
||||
import { domainRouter } from '@api/routes/domain/domain';
|
||||
@@ -42,19 +41,21 @@ export const app = new Hono()
|
||||
.use('*', logger())
|
||||
.use('*', prettyJSON())
|
||||
.use('*', secureHeaders())
|
||||
.use(
|
||||
'*',
|
||||
cors({
|
||||
origin: (origin) => resolveTrustedBrowserOriginForCors(origin),
|
||||
allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
allowHeaders: ['Content-Type', 'Authorization', 'Cio-org-id'],
|
||||
exposeHeaders: ['Content-Length', 'X-Kuma-Revision'],
|
||||
maxAge: 600,
|
||||
credentials: true
|
||||
})
|
||||
)
|
||||
.use('*', async (c, next) => {
|
||||
if (isPublicApiPath(c.req.path)) return next();
|
||||
|
||||
return sessionCors(c, next);
|
||||
})
|
||||
.use('*', rateLimiter)
|
||||
.use('*', async (c, next) => {
|
||||
if (isPublicApiPath(c.req.path)) {
|
||||
c.set('user', null);
|
||||
c.set('session', null);
|
||||
c.set('orgRoles', {});
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
let session: Awaited<ReturnType<typeof auth.api.getSession>> | null = null;
|
||||
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { cors } from 'hono/cors';
|
||||
import { resolveTrustedBrowserOriginForCors } from '@api/utils/origins';
|
||||
|
||||
const sharedCorsOptions = {
|
||||
allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
allowHeaders: ['Content-Type', 'Authorization', 'Cio-org-id'],
|
||||
exposeHeaders: ['Content-Length', 'X-Kuma-Revision'],
|
||||
maxAge: 600
|
||||
};
|
||||
|
||||
/**
|
||||
* Bearer-token routes meant to be called from any third-party origin (no cookies).
|
||||
* `*` is safe here because `credentials` is off — the browser will reject a Set-Cookie roundtrip.
|
||||
*/
|
||||
export const publicApiCors = cors({
|
||||
...sharedCorsOptions,
|
||||
origin: '*',
|
||||
credentials: false
|
||||
});
|
||||
|
||||
/**
|
||||
* Cookie/session routes (dashboard RPC, Better Auth, org dashboards).
|
||||
* Allowed origins: configured `TRUSTED_ORIGINS`, `*.classroomio.com`, verified custom domains.
|
||||
*/
|
||||
export const sessionCors = cors({
|
||||
...sharedCorsOptions,
|
||||
origin: (origin) => resolveTrustedBrowserOriginForCors(origin),
|
||||
credentials: true
|
||||
});
|
||||
|
||||
/** Path prefix considered "public REST API" for CORS / session bypass. */
|
||||
export const PUBLIC_API_PATH_PREFIX = '/public-api/';
|
||||
|
||||
export function isPublicApiPath(path: string): boolean {
|
||||
return path.startsWith(PUBLIC_API_PATH_PREFIX);
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
import { Hono } from '@api/utils/hono';
|
||||
import { publicApiCors } from '@api/middlewares/cors';
|
||||
import { v1AudienceRouter } from './audience';
|
||||
import { v1CoursesRouter } from './courses';
|
||||
|
||||
export const v1Router = new Hono().route('/audience', v1AudienceRouter).route('/courses', v1CoursesRouter);
|
||||
export const v1Router = new Hono()
|
||||
.use('*', publicApiCors)
|
||||
.route('/audience', v1AudienceRouter)
|
||||
.route('/courses', v1CoursesRouter);
|
||||
|
||||
@@ -38,6 +38,11 @@ class AppInitApi extends BaseApi {
|
||||
|
||||
async setupApp(locals: App.Locals, params: AppSetupParams): Promise<boolean | undefined> {
|
||||
if (!locals.user) {
|
||||
if (!params.isOrgSite) {
|
||||
goto(resolve('/login', {}));
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('No user found in locals');
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user