Redirecting to fp/install and fp/auth on missing token
This commit is contained in:
parent
0189726503
commit
0ab0cc563e
|
|
@ -18,6 +18,7 @@ COPY server/index.js ./
|
||||||
COPY server/fdk.js ./
|
COPY server/fdk.js ./
|
||||||
COPY server/postgresFdkStorage.js ./
|
COPY server/postgresFdkStorage.js ./
|
||||||
COPY server/config ./config
|
COPY server/config ./config
|
||||||
|
# Includes protected and public platform routes such as routes/platformPublic.js.
|
||||||
COPY server/routes ./routes
|
COPY server/routes ./routes
|
||||||
COPY server/services ./services
|
COPY server/services ./services
|
||||||
COPY --from=client-build /client/dist ./public
|
COPY --from=client-build /client/dist ./public
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import { getRuntimeApplicationId, getRuntimeCompanyId } from './runtimeContext';
|
||||||
|
|
||||||
const FDK_BOOTSTRAP_ATTEMPT_PREFIX = 'sms_fdk_bootstrap_attempt';
|
const FDK_BOOTSTRAP_ATTEMPT_PREFIX = 'sms_fdk_bootstrap_attempt';
|
||||||
const FDK_BOOTSTRAP_TTL_MS = 2 * 60 * 1000;
|
const FDK_BOOTSTRAP_TTL_MS = 2 * 60 * 1000;
|
||||||
|
const FDK_BOOTSTRAP_REDIRECT_CODE = 'FDK_AUTH_BOOTSTRAP_REDIRECT';
|
||||||
|
const FDK_SESSION_UNAVAILABLE_CODE = 'FDK_SESSION_UNAVAILABLE';
|
||||||
|
|
||||||
function getBootstrapStorageKey(companyId) {
|
function getBootstrapStorageKey(companyId) {
|
||||||
return `${FDK_BOOTSTRAP_ATTEMPT_PREFIX}:${companyId}`;
|
return `${FDK_BOOTSTRAP_ATTEMPT_PREFIX}:${companyId}`;
|
||||||
|
|
@ -63,14 +65,57 @@ function buildFdkInstallUrl(companyId) {
|
||||||
|
|
||||||
function createBootstrapRedirectError() {
|
function createBootstrapRedirectError() {
|
||||||
const error = new Error('Redirecting to FDK auth bootstrap');
|
const error = new Error('Redirecting to FDK auth bootstrap');
|
||||||
error.code = 'FDK_AUTH_BOOTSTRAP_REDIRECT';
|
error.code = FDK_BOOTSTRAP_REDIRECT_CODE;
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createSessionUnavailableError(message = 'FDK session is unavailable') {
|
||||||
|
const error = new Error(message);
|
||||||
|
error.code = FDK_SESSION_UNAVAILABLE_CODE;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldAttemptBootstrap(sessionStatus = {}) {
|
||||||
|
return Boolean(sessionStatus?.configured) && Boolean(sessionStatus?.needsBootstrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getSessionStatus() {
|
||||||
|
const response = await apiClient.get('/api/platform/session-status');
|
||||||
|
return response?.data || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureFdkPlatformSession(companyId) {
|
||||||
|
if (!companyId) {
|
||||||
|
throw createSessionUnavailableError('Missing company id for FDK session bootstrap');
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessionStatus = await getSessionStatus();
|
||||||
|
if (sessionStatus?.authenticated) {
|
||||||
|
clearBootstrapAttempt(companyId);
|
||||||
|
return sessionStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldAttemptBootstrap(sessionStatus) && shouldBootstrapSession(companyId)) {
|
||||||
|
const installUrl = buildFdkInstallUrl(companyId);
|
||||||
|
if (installUrl && typeof window !== 'undefined') {
|
||||||
|
writeBootstrapAttempt(companyId);
|
||||||
|
window.location.replace(installUrl);
|
||||||
|
throw createBootstrapRedirectError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw createSessionUnavailableError(
|
||||||
|
sessionStatus?.reason
|
||||||
|
? `FDK session unavailable: ${sessionStatus.reason}`
|
||||||
|
: 'FDK session is unavailable'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchActiveSalesChannels() {
|
export async function fetchActiveSalesChannels() {
|
||||||
const companyId = getRuntimeCompanyId();
|
const companyId = getRuntimeCompanyId();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
await ensureFdkPlatformSession(companyId);
|
||||||
const response = await apiClient.get('/api/platform/sales-channels');
|
const response = await apiClient.get('/api/platform/sales-channels');
|
||||||
clearBootstrapAttempt(companyId);
|
clearBootstrapAttempt(companyId);
|
||||||
return normalizeChannelsPayload(
|
return normalizeChannelsPayload(
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ const path = require('path');
|
||||||
|
|
||||||
const businessesRoutes = require('./routes/businesses');
|
const businessesRoutes = require('./routes/businesses');
|
||||||
const platformRoutes = require('./routes/platform');
|
const platformRoutes = require('./routes/platform');
|
||||||
|
const platformPublicRoutes = require('./routes/platformPublic');
|
||||||
const { fdkExtension, isFdkConfigured } = require('./fdk');
|
const { fdkExtension, isFdkConfigured } = require('./fdk');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
@ -29,9 +30,11 @@ app.get('/api/health', (req, res) => res.json({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (fdkExtension) {
|
if (fdkExtension) {
|
||||||
|
app.use('/api/platform', platformPublicRoutes);
|
||||||
app.use(fdkExtension.fdkHandler);
|
app.use(fdkExtension.fdkHandler);
|
||||||
app.use('/api/platform', fdkExtension.platformApiRoutes, platformRoutes);
|
app.use('/api/platform', fdkExtension.platformApiRoutes, platformRoutes);
|
||||||
} else {
|
} else {
|
||||||
|
app.use('/api/platform', platformPublicRoutes);
|
||||||
app.use('/api/platform', platformRoutes);
|
app.use('/api/platform', platformRoutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
const express = require('express');
|
||||||
|
const { SESSION_COOKIE_NAME } = require('@gofynd/fdk-extension-javascript/express/constants');
|
||||||
|
|
||||||
|
const { fdkExtension, isFdkConfigured } = require('../fdk');
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
function normalizeText(value) {
|
||||||
|
return typeof value === 'string' ? value.trim() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCompanyId(req) {
|
||||||
|
return normalizeText(
|
||||||
|
req.get('x-company-id')
|
||||||
|
|| req.query.company_id
|
||||||
|
|| req.query.companyId
|
||||||
|
|| ''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSessionCookieName(companyId) {
|
||||||
|
return `${SESSION_COOKIE_NAME}_${companyId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearSessionCookie(res, companyId) {
|
||||||
|
res.clearCookie(getSessionCookieName(companyId), {
|
||||||
|
path: '/',
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: 'None',
|
||||||
|
partitioned: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
router.get('/session-status', async (req, res) => {
|
||||||
|
const companyId = getCompanyId(req);
|
||||||
|
|
||||||
|
if (!isFdkConfigured || !fdkExtension) {
|
||||||
|
return res.json({
|
||||||
|
configured: false,
|
||||||
|
authenticated: false,
|
||||||
|
companyId,
|
||||||
|
needsBootstrap: false,
|
||||||
|
reason: 'fdk_not_configured',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!companyId) {
|
||||||
|
return res.status(400).json({
|
||||||
|
configured: true,
|
||||||
|
authenticated: false,
|
||||||
|
companyId: '',
|
||||||
|
needsBootstrap: false,
|
||||||
|
reason: 'missing_company_id',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessionCookieName = getSessionCookieName(companyId);
|
||||||
|
const sessionId = normalizeText(req.signedCookies?.[sessionCookieName] || '');
|
||||||
|
|
||||||
|
if (!sessionId) {
|
||||||
|
return res.json({
|
||||||
|
configured: true,
|
||||||
|
authenticated: false,
|
||||||
|
companyId,
|
||||||
|
needsBootstrap: true,
|
||||||
|
reason: 'missing_session_cookie',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const session = await fdkExtension.storage.get(sessionId);
|
||||||
|
const authenticated = Boolean(
|
||||||
|
session
|
||||||
|
&& normalizeText(String(session.company_id || '')) === companyId
|
||||||
|
&& normalizeText(session.access_token || '')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!authenticated) {
|
||||||
|
clearSessionCookie(res, companyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
configured: true,
|
||||||
|
authenticated,
|
||||||
|
companyId,
|
||||||
|
needsBootstrap: !authenticated,
|
||||||
|
reason: authenticated ? 'ok' : 'missing_or_invalid_session',
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(503).json({
|
||||||
|
configured: true,
|
||||||
|
authenticated: false,
|
||||||
|
companyId,
|
||||||
|
needsBootstrap: false,
|
||||||
|
reason: 'session_status_error',
|
||||||
|
error: error.message || 'Failed to inspect FDK session',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
Loading…
Reference in New Issue
Block a user