198 lines
6.6 KiB
JavaScript
198 lines
6.6 KiB
JavaScript
const express = require('express');
|
|
const cookieParser = require('cookie-parser');
|
|
const morgan = require('morgan');
|
|
const path = require('path');
|
|
const session = require('express-session');
|
|
const dotenv = require('dotenv');
|
|
dotenv.config();
|
|
const bodyParser = require('body-parser');
|
|
const dbConnect = require('./db/index');
|
|
const cors = require('cors');
|
|
const passport = require('passport');
|
|
// const FileStore = require('session-file-store')(session);
|
|
|
|
const helmet = require('helmet');
|
|
|
|
const mainRouter = require('./routes/mainRouter');
|
|
const archiveRouter = require('./routes/archiveRouter');
|
|
const authRouter = require('./routes/authRouter.js');
|
|
const passportConfig = require('./passport/index.js');
|
|
const commonRouter = require('./routes/commonRouter.js');
|
|
const officialDocRouter = require('./routes/officialDocRouter.js');
|
|
const overviewRouter = require('./routes/overviewRouter.js');
|
|
const bullBoardRouter = require('./routes/bullBoardRouter.js');
|
|
const gsimRouter = require('./routes/gsimRouter.js');
|
|
|
|
//test
|
|
const oauthRouter = require('./oauth/oauthRouter.js');
|
|
const { isLoggedIn, deserializeUser } = require('./oauth/oauthController');
|
|
|
|
const logger = require('./logger');
|
|
|
|
const app = express();
|
|
|
|
const env = process.env.NODE_ENV;
|
|
|
|
dbConnect(); // DB 연결
|
|
passportConfig(); // passport 설정
|
|
|
|
// app.use(
|
|
// helmet({
|
|
// contentSecurityPolicy: false, // CSP는 비활성화
|
|
// crossOriginEmbedderPolicy: false, // 외부 CDN 자원 쓰면 충돌 날 수 있음
|
|
// })
|
|
// );
|
|
|
|
const ALLOWED_PARENTS = [
|
|
"http://bcmf.hanmaceng.co.kr",
|
|
"https://bcmf.hanmaceng.co.kr",
|
|
"http://*.hanmaceng.co.kr",
|
|
"https://*.hanmaceng.co.kr",
|
|
];
|
|
|
|
app.use(helmet({
|
|
frameguard: false, // X-Frame-Options 제거
|
|
contentSecurityPolicy: false, // CSP는 직접 세팅
|
|
crossOriginEmbedderPolicy: false,
|
|
}));
|
|
|
|
app.use((req, res, next) => {
|
|
res.setHeader(
|
|
"Content-Security-Policy",
|
|
`frame-ancestors 'self' ${ALLOWED_PARENTS.join(' ')}`
|
|
);
|
|
next();
|
|
});
|
|
|
|
|
|
//페이로드 크기 설정 => upload check할때 json 용량때문에 사용
|
|
app.use(bodyParser.json({limit : '50mb'}));
|
|
app.use(bodyParser.urlencoded({limit : '50mb', extended:true}));
|
|
|
|
app.use(cors());
|
|
app.use(morgan('dev'));
|
|
|
|
app.use('/node_modules', express.static(path.join(__dirname, 'node_modules')));
|
|
app.use('/libs', express.static(path.join(__dirname, 'libs')));
|
|
app.use('/', express.static(path.join(__dirname, 'views')));
|
|
app.use(express.static(__dirname + '/node_modules/socket.io/client-dist'));
|
|
app.use('/:projectId',express.static(__dirname + '/node_modules/socket.io/client-dist'));
|
|
// app.use('/PM_ver4', express.static(env != 'production'?'D:\\PM_ver4':'D:\\PM_ver4')); // D드라이브 폴더 사용
|
|
|
|
// 동적 API 및 라우트 캐싱 방지 설정 (304 Cache로 인한 이전 에러 응답 물림 및 리다이렉트 캐싱 방지)
|
|
app.use((req, res, next) => {
|
|
if (req.method === 'GET' && !req.path.includes('.') && !req.path.startsWith('/node_modules') && !req.path.startsWith('/libs')) {
|
|
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
res.setHeader('Pragma', 'no-cache');
|
|
res.setHeader('Expires', '0');
|
|
}
|
|
next();
|
|
});
|
|
|
|
app.use(express.json());
|
|
app.use(express.urlencoded({extended:false}));
|
|
app.use(cookieParser(process.env.COOKIE_SECRET));
|
|
|
|
// const fileStoreOptions = {
|
|
// path:`C:\\develop\\session`,
|
|
// ttl:1000*60*60*24,
|
|
// logFn: function(){},
|
|
// retries:5
|
|
// }
|
|
// app.use(session({
|
|
// store: new FileStore(fileStoreOptions), // FileStore를 사용하도록 설정
|
|
// secret: 'testkey', // 세션 ID를 서명하는 데 사용되는 비밀 키 (필수)
|
|
// resave: false, // 세션 데이터가 변경되지 않아도 세션을 다시 저장할지 여부
|
|
// saveUninitialized: false, // 초기화되지 않은 세션을 저장소에 저장할지 여부
|
|
// cookie: {
|
|
// maxAge: 1000 * 60 * 60 * 24 // 24시간 후 쿠키 만료
|
|
// }
|
|
// }));
|
|
|
|
|
|
app.use(session({
|
|
resave: false,
|
|
saveUninitialized: false,
|
|
secret: process.env.COOKIE_SECRET,
|
|
cookie: {
|
|
httpOnly: true,
|
|
secure: false,
|
|
// maxAge: (24 * 60 * 60 * 1000) + (9 * 3600 * 1000)
|
|
}
|
|
}));
|
|
|
|
//passport 초기화
|
|
app.use(passport.initialize()); // passport 설정을 심음
|
|
app.use(passport.session()); // req.session에 passport 정보를 저장
|
|
|
|
app.post('/log-client-error', express.json(), (req, res) => {
|
|
const { message, source, lineno, colno, stack } = req.body;
|
|
console.error('🚨 [CLIENT ERROR]:', message);
|
|
console.error(` at ${source}:${lineno}:${colno}`);
|
|
if (stack) console.error(stack);
|
|
res.sendStatus(200);
|
|
});
|
|
|
|
// 라우터
|
|
app.use(`/oauth`, oauthRouter);
|
|
app.use('/login', (req, res) => {
|
|
res.redirect('/user/login');
|
|
});
|
|
app.use('/user/login', (req, res, next) =>{res.sendFile(path.join(process.cwd()+`/views/login/login.html`))});
|
|
// app.use('/popup' ,(req,res,next)=>{res.sendFile(path.join(process.cwd()+`/views/main/popup.html`))})
|
|
|
|
// 글로벌 사용자 세션 역직렬화 (로그인 상태 복원)
|
|
app.use(deserializeUser);
|
|
|
|
// 공공 라우트 및 인증 API
|
|
app.use('/auth', authRouter);
|
|
|
|
// 어드민 화면 서빙 및 권한 통제
|
|
const isAdminLocal = (req, res, next) => {
|
|
const userGroup = req.user?.group;
|
|
if (req.user && (userGroup === 'USER_GROUP_super' || userGroup === 'dev' || userGroup === 'super')) {
|
|
return next();
|
|
}
|
|
return res.status(403).send("어드민(super) 권한이 필요합니다.");
|
|
};
|
|
app.get('/admin', isLoggedIn, isAdminLocal, (req, res) => {
|
|
res.sendFile(path.join(process.cwd(), 'views/admin/dashboard.html'));
|
|
});
|
|
|
|
// 로그인 보호 장벽 적용 (이하 라우트는 로그인 세션 필수)
|
|
app.use(isLoggedIn);
|
|
|
|
app.use('/', mainRouter);
|
|
app.use('/:projectId/archive', archiveRouter);
|
|
app.use('/:projectId/overview', overviewRouter);
|
|
app.use('/:projectId/officialDoc', officialDocRouter);
|
|
app.use('/common', commonRouter);
|
|
|
|
app.use('/gsim', gsimRouter);
|
|
|
|
// 어드민 전용 REST API
|
|
app.use('/api/admin', require('./routes/admin/adminRouter'));
|
|
|
|
// BullMQ 모니터링 대시보드
|
|
app.use('/admin/queues', bullBoardRouter);
|
|
|
|
// 404응답 미들웨어
|
|
app.use((req, res, next) => {
|
|
const error = new Error(`${req.method} ${req.url} 라우터가 없어요`);
|
|
error.status = 404;
|
|
logger.error(error.message);
|
|
next(error);
|
|
});
|
|
|
|
// 에러 처리 미들웨어
|
|
app.use((err, req, res, next) => {
|
|
console.error(err.stack);
|
|
logger.error(err.message);
|
|
res.status(err.status || 500).send(`status code: ${err.status || 500} 에러가 났어요`)
|
|
});
|
|
|
|
// 자동 보관 및 자동 삭제 스케줄러 가동
|
|
const scheduler = require('./libs/scheduler');
|
|
scheduler.start();
|
|
|
|
module.exports = app; |