보안설정 수정, 모바일 최적화 변경

This commit is contained in:
2025-06-11 03:33:44 +09:00
parent d085e037a1
commit 48f1bf1c52
10 changed files with 339 additions and 141 deletions
+46 -6
View File
@@ -25,7 +25,29 @@ const io = socketIo(server, {
}
});
app.use(cors());
function getDomain(origin) {
try {
const url = new URL(origin);
return url.hostname; // 'lanebow.com', 'localhost'
} catch (e) {
return null;
}
}
const allowedDomains = ['lanebow.com', 'localhost'];
app.use(cors({
origin: function(origin, callback) {
if (!origin) return callback(null, true);
const domain = getDomain(origin);
if (allowedDomains.includes(domain)) {
return callback(null, true);
} else {
return callback(new Error('Not allowed by CORS'), false);
}
},
credentials: true
}));
app.use(bodyParser.json());
// Socket.IO 연결 처리
@@ -82,17 +104,35 @@ const options = {
// MySQL 세션 저장소 생성
const sessionStore = new MySQLStore(options);
app.use(session({
const baseSessionOptions = {
key: 'bowling_session',
secret: process.env.JWT_SECRET,
store: sessionStore,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
maxAge: 24 * 60 * 60 * 1000 // 1일
cookie: {
maxAge: 24 * 60 * 60 * 1000,
secure: false,
sameSite: 'lax'
}
}));
};
app.use(session(baseSessionOptions));
// 요청마다 secure/sameSite를 동적으로 할당
app.use((req, res, next) => {
const origin = req.headers.origin;
const domain = getDomain(origin);
if (req.session && req.session.cookie) {
if (domain === 'lanebow.com') {
req.session.cookie.secure = true;
req.session.cookie.sameSite = 'none';
} else {
req.session.cookie.secure = false;
req.session.cookie.sameSite = 'lax';
}
}
next();
});
// 데이터베이스 연결 및 모델 동기화 실행
sequelize.authenticate()
+7 -25
View File
@@ -54,6 +54,7 @@ exports.selectClub = async (req, res) => {
}
req.session.clubId = clubId;
console.log(`Session clubId: ${clubId}`);
res.status(200).json({ message: '클럽을 선택했습니다.' });
} catch (error) {
console.error('클럽 선택 오류:', error);
@@ -136,18 +137,18 @@ exports.getClubById = async (req, res) => {
// 새 클럽 생성
exports.createClub = async (req, res) => {
try {
const { name, location, description, ownerEmail, contact, features, sendInvite } = req.body;
const { name, location, description, averageCalculationPeriod } = req.body;
// 필수 필드 검증
if (!name || !ownerEmail) {
return res.status(400).json({ message: '클럽 이름과 모임장 이메일은 필수 항목입니다.' });
if (!name) {
return res.status(400).json({ message: '클럽 이름은 필수 항목입니다.' });
}
// 이메일로 사용자 조회
const owner = await User.findOne({ where: { email: ownerEmail } });
const owner = await User.findOne({ where: { id: req.user.id } });
if (!owner) {
return res.status(404).json({ message: '해당 이메일로 등록된 사용자를 찾을 수 없습니다.' });
return res.status(404).json({ message: '해당 사용자를 찾을 수 없습니다.' });
}
// 클럽 생성
@@ -155,7 +156,7 @@ exports.createClub = async (req, res) => {
name,
location,
description,
contact,
averageCalculationPeriod,
ownerId: owner.id,
memberCount: 1, // 모임장 포함
status: 'active'
@@ -172,25 +173,6 @@ exports.createClub = async (req, res) => {
status: 'active'
});
// 선택된 기능 추가
if (features && features.length > 0) {
const featurePromises = features.map(featureId =>
ClubFeature.create({
clubId: newClub.id,
featureId,
enabled: true
})
);
await Promise.all(featurePromises);
}
// 초대 이메일 발송 로직 (sendInvite가 true인 경우)
if (sendInvite) {
// TODO: 초대 이메일 발송 로직 구현
console.log(`${ownerEmail}에게 초대 이메일 발송 예정`);
}
// 베이직 1개월 플랜 자동 추가
try {
// 베이직 플랜 조회 (ID가 1이라고 가정, 실제 환경에 맞게 조정 필요)