v1.10.88 품질·보안 개선과 미디어 카탈로그 database 전환을 반영한다.
세션·로그인 제한, ZIP/업로드 스트리밍, CSP 최소 강제와 Report-Only, Playwright 격리 검증을 추가하고 미디어 목록을 reconcile 후 database 모드로 고정한다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -130,6 +130,7 @@ const mapAdminMemberRow = (row) => {
|
||||
* @property {string} avatarUrl - 아바타 URL
|
||||
* @property {boolean} isAdmin - 관리자 여부
|
||||
* @property {'owner' | 'admin' | 'vip' | 'member'} role - 권한 코드
|
||||
* @property {number} sessionVersion - 세션 무효화 버전
|
||||
* @property {string} createdAt - 생성 시각(ISO)
|
||||
* @property {string} updatedAt - 수정 시각(ISO)
|
||||
* @property {string | null} lastSeenAt - 최근 접속 시각(ISO)
|
||||
@@ -169,6 +170,7 @@ export const getUserByEmail = async (email) => {
|
||||
avatar_url AS "avatarUrl",
|
||||
is_admin AS "isAdmin",
|
||||
user_role AS "role",
|
||||
session_version AS "sessionVersion",
|
||||
created_at AS "createdAt",
|
||||
updated_at AS "updatedAt",
|
||||
last_seen_at AS "lastSeenAt",
|
||||
@@ -313,6 +315,7 @@ export const createUser = async (input) => {
|
||||
avatar_url AS "avatarUrl",
|
||||
is_admin AS "isAdmin",
|
||||
user_role AS "role",
|
||||
session_version AS "sessionVersion",
|
||||
created_at AS "createdAt",
|
||||
updated_at AS "updatedAt",
|
||||
last_seen_at AS "lastSeenAt",
|
||||
@@ -367,6 +370,7 @@ export const upsertBootstrapOwner = async (input) => {
|
||||
UPDATE users
|
||||
SET
|
||||
password_hash = ${input.passwordHash},
|
||||
session_version = session_version + 1,
|
||||
is_admin = true,
|
||||
user_role = ${MEMBER_ROLE.OWNER},
|
||||
updated_at = now()
|
||||
@@ -379,6 +383,7 @@ export const upsertBootstrapOwner = async (input) => {
|
||||
avatar_url AS "avatarUrl",
|
||||
is_admin AS "isAdmin",
|
||||
user_role AS "role",
|
||||
session_version AS "sessionVersion",
|
||||
created_at AS "createdAt",
|
||||
updated_at AS "updatedAt",
|
||||
last_seen_at AS "lastSeenAt",
|
||||
@@ -406,6 +411,7 @@ export const upsertBootstrapOwner = async (input) => {
|
||||
avatar_url AS "avatarUrl",
|
||||
is_admin AS "isAdmin",
|
||||
user_role AS "role",
|
||||
session_version AS "sessionVersion",
|
||||
created_at AS "createdAt",
|
||||
updated_at AS "updatedAt",
|
||||
last_seen_at AS "lastSeenAt",
|
||||
@@ -480,6 +486,7 @@ export const updateMemberPasswordByEmail = async (input) => {
|
||||
UPDATE users
|
||||
SET
|
||||
password_hash = ${input.passwordHash},
|
||||
session_version = session_version + 1,
|
||||
updated_at = now()
|
||||
WHERE lower(email) = lower(${input.email})
|
||||
RETURNING id
|
||||
@@ -499,6 +506,7 @@ export const updateMemberPassword = async (input) => {
|
||||
UPDATE users
|
||||
SET
|
||||
password_hash = ${input.passwordHash},
|
||||
session_version = session_version + 1,
|
||||
updated_at = now()
|
||||
WHERE id = ${input.userId}
|
||||
`
|
||||
@@ -787,6 +795,7 @@ export const getAdminUserByEmail = async (email) => {
|
||||
avatar_url AS "avatarUrl",
|
||||
is_admin AS "isAdmin",
|
||||
user_role AS "role",
|
||||
session_version AS "sessionVersion",
|
||||
created_at AS "createdAt",
|
||||
updated_at AS "updatedAt",
|
||||
last_seen_at AS "lastSeenAt",
|
||||
@@ -826,16 +835,37 @@ export const getMemberBootstrapState = async () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 관리자 권한을 가진 회원 여부를 확인한다.
|
||||
* 회원 세션 버전이 현재 DB 값과 일치하는지 확인한다.
|
||||
* @param {string} userId - 사용자 ID
|
||||
* @returns {Promise<boolean>} 관리자 권한 여부
|
||||
* @param {number} sessionVersion - 세션 토큰 버전
|
||||
* @returns {Promise<boolean>} 현재 세션 여부
|
||||
*/
|
||||
export const isPrivilegedMember = async (userId) => {
|
||||
export const isMemberSessionCurrent = async (userId, sessionVersion) => {
|
||||
const sql = requireSql()
|
||||
const rows = await sql`
|
||||
SELECT id
|
||||
FROM users
|
||||
WHERE id = ${userId}
|
||||
AND session_version = ${sessionVersion}
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
return Boolean(rows?.[0])
|
||||
}
|
||||
|
||||
/**
|
||||
* 관리자 권한과 세션 버전을 함께 확인한다.
|
||||
* @param {string} userId - 사용자 ID
|
||||
* @param {number} sessionVersion - 세션 토큰 버전
|
||||
* @returns {Promise<boolean>} 현재 관리자 세션 여부
|
||||
*/
|
||||
export const isPrivilegedMemberSession = async (userId, sessionVersion) => {
|
||||
const sql = requireSql()
|
||||
const rows = await sql`
|
||||
SELECT id
|
||||
FROM users
|
||||
WHERE id = ${userId}
|
||||
AND session_version = ${sessionVersion}
|
||||
AND user_role = ANY(${PRIVILEGED_ROLES})
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
Reference in New Issue
Block a user