This commit is contained in:
payacom
2026-10-02 18:13:34 +03:30
parent d4ebc20aa8
commit fade8543e2
9 changed files with 180 additions and 63 deletions

View File

@@ -14,7 +14,7 @@ const {
consumeFreeCreation,
freeCreationLimitResponse
} = require('../../../utils/freeCreationLimit')
const { canUseFreeBillboard, consumeFreeBillboard } = require('../../../utils/billboardFreeLimit')
const { tryConsumeFreeBillboard } = require('../../../utils/billboardFreeLimit')
const {
PROJECT_ACCEPT_RATE,
PROJECT_COMPLETION_COMMISSION_RATE,
@@ -64,6 +64,18 @@ const initiatePayment = async (req, res) => {
const itemName = req.body.item_name // Get item name from request body
const price = await getPriceFromDatabase(itemName) // Get price from database
const projectId = req.body.projectId // Get project ID from request body
// IDOR: قبلاً هیچ‌جا چک نمی‌شد که این پروژه واقعاً متعلق به همین کاربرِ
// احرازهویت‌شده‌ست — یه projectId دلخواه کافی بود تا کاربرِ دیگه‌ای پرداخت کنه
// ولی پروژه‌ی یه کاربرِ کاملاً متفاوت تایید/پرداخت‌شده بشه
const projectForOwnerCheck = await ProjectModel.findById(projectId).select('creator_id')
if (!projectForOwnerCheck) {
return res.status(404).json({ message: 'پروژه یافت نشد' })
}
if (String(projectForOwnerCheck.creator_id) !== String(userId)) {
return res.status(403).json({ message: 'دسترسی به این پروژه ندارید' })
}
// Save project ID for later use in callback URL
req.session.projectId = projectId
const item = await TypeAndPriceModel.findOne({ name: itemName })
@@ -641,15 +653,24 @@ const initiateAdvertisingPayment = async (req, res) => {
const advertisingId = req.body.advertisingId // Get project ID from request body
const showDiscount = req.body.showDiscount
// IDOR: قبلاً هیچ‌جا چک نمی‌شد که این بیلبورد واقعاً متعلق به همین کاربرِ
// احرازهویت‌شده‌ست — یه advertisingId دلخواه کافی بود تا کاربرِ دیگه‌ای پرداخت
// کنه ولی بیلبوردِ یه کاربرِ کاملاً متفاوت تایید/پرداخت‌شده بشه
const advertisingForOwnerCheck = await AdvertisingModel.findById(advertisingId).select('creator_id')
if (!advertisingForOwnerCheck) {
return res.status(404).json({ message: 'بیلبورد یافت نشد' })
}
if (String(advertisingForOwnerCheck.creator_id) !== String(userId)) {
return res.status(403).json({ message: 'دسترسی به این بیلبورد ندارید' })
}
// Save project ID for later use in callback URL
req.session.advertisingId = advertisingId
const item = await AdvertisingTypeModel.findOne({ name: itemName })
const user = await UserModel.findById(userId)
if (item.name === 'free' && item.price === 0) {
if (canUseFreeBillboard(user)) {
await consumeFreeBillboard(user)
await user.save()
const freeResult = await tryConsumeFreeBillboard(UserModel, userId)
if (freeResult.ok) {
const project = await AdvertisingModel.findById(advertisingId)
if (!project) {
res.status(404).send('Advertising not found')
@@ -660,7 +681,7 @@ const initiateAdvertisingPayment = async (req, res) => {
await project.save()
res.status(200).json({ message: 'بیلبورد رایگان با موفقیت ایجاد شد', advertisingId, type: 'free' })
} else {
res.status(403).json({ message: 'سقف ۲۰۰ بیلبورد رایگان شما به پایان رسیده است.' })
res.status(403).json({ message: freeResult.message })
}
} else {
const response = await axios.post(
@@ -796,12 +817,10 @@ const republishAdvertisingPayment = async (req, res) => {
// Save project ID for later use in callback URL
req.session.advertisingId = advertisingId
const item = await AdvertisingTypeModel.findOne({ name: itemName })
const user = await UserModel.findById(userId)
if (item.name === 'free' && item.price === 0) {
if (canUseFreeBillboard(user)) {
await consumeFreeBillboard(user)
await user.save()
const freeResult = await tryConsumeFreeBillboard(UserModel, userId)
if (freeResult.ok) {
const project = await AdvertisingModel.findById(advertisingId)
if (!project) {
res.status(404).send('Advertising not found')
@@ -812,7 +831,7 @@ const republishAdvertisingPayment = async (req, res) => {
await project.save()
res.status(200).json({ message: 'بیلبورد رایگان با موفقیت ایجاد شد', advertisingId, type: 'free' })
} else {
res.status(403).json({ message: 'سقف ۲۰۰ بیلبورد رایگان شما به پایان رسیده است.' })
res.status(403).json({ message: freeResult.message })
}
} else {
const response = await axios.post(

View File

@@ -9,7 +9,7 @@ const NotificationModel = require('../../../models/NotificationModel')
const UserModel = require('../../../models/UserModel')
const AdvertisingTypeModel = require('../../../models/AdvertisingTypeModel')
const AdvertisingModel = require('../../../models/AdvertisingModel')
const { canUseFreeBillboard, consumeFreeBillboard } = require('../../../utils/billboardFreeLimit')
const { tryConsumeFreeBillboard } = require('../../../utils/billboardFreeLimit')
const OfferTypeModel = require('../../../models/OfferTypeModel')
const OfferModel = require('../../../models/OfferModel')
const { default: axios } = require('axios')
@@ -92,6 +92,17 @@ const initiatePaymentWeb = async (req, res) => {
})
}
// IDOR: قبلاً هیچ‌جا چک نمی‌شد که این پروژه واقعاً متعلق به همین کاربرِ
// احرازهویت‌شده‌ست — یه projectId دلخواه (مثلاً از یه لینکِ ساختگی) کافی بود تا
// کاربرِ دیگه‌ای پرداخت کنه ولی پروژه‌ی یه کاربرِ کاملاً متفاوت تایید/پرداخت‌شده بشه
const projectForOwnerCheck = await ProjectModel.findById(projectId).select('creator_id')
if (!projectForOwnerCheck) {
return res.status(404).json({ error: true, message: 'پروژه یافت نشد' })
}
if (String(projectForOwnerCheck.creator_id) !== String(userId)) {
return res.status(403).json({ error: true, message: 'دسترسی به این پروژه ندارید' })
}
const price = Number(item.price) || 0
const user = await UserModel.findById(userId)
if (!user) {
@@ -566,16 +577,25 @@ const initiateAdvertisingPaymentWeb = async (req, res) => {
const advertisingId = req.body.advertisingId // Get project ID from request body
const showDiscount = req.body.showDiscount
// IDOR: قبلاً هیچ‌جا چک نمی‌شد که این بیلبورد واقعاً متعلق به همین کاربرِ
// احرازهویت‌شده‌ست — یه advertisingId دلخواه کافی بود تا کاربرِ دیگه‌ای پرداخت
// کنه ولی بیلبوردِ یه کاربرِ کاملاً متفاوت تایید/پرداخت‌شده بشه (رایگان بود، فقط
// با مصرفِ سهمیه‌ی رایگانِ همون کاربر هم ممکن بود)
const advertisingForOwnerCheck = await AdvertisingModel.findById(advertisingId).select('creator_id')
if (!advertisingForOwnerCheck) {
return res.status(404).json({ message: 'بیلبورد یافت نشد' })
}
if (String(advertisingForOwnerCheck.creator_id) !== String(userId)) {
return res.status(403).json({ message: 'دسترسی به این بیلبورد ندارید' })
}
// Save project ID for later use in callback URL
req.session.advertisingId = advertisingId
const item = await AdvertisingTypeModel.findOne({ name: itemName })
const user = await UserModel.findById(userId)
if (item.name === 'free' && item.price === 0) {
if (canUseFreeBillboard(user)) {
await consumeFreeBillboard(user)
// updateOne + $inc به‌جای user.save() — رجوع کنید به توضیح مشابه در initiateOfferPaymentWeb
await UserModel.updateOne({ _id: userId }, { $inc: { free_billboard_count: 1 } })
const freeResult = await tryConsumeFreeBillboard(UserModel, userId)
if (freeResult.ok) {
const project = await AdvertisingModel.findById(advertisingId)
if (!project) {
res.status(404).send('Advertising not found')
@@ -586,7 +606,7 @@ const initiateAdvertisingPaymentWeb = async (req, res) => {
await project.save()
res.status(200).json({ message: 'بیلبورد رایگان با موفقیت ایجاد شد', advertisingId, type: 'free' })
} else {
res.status(403).json({ message: 'سقف ۲۰۰ بیلبورد رایگان شما به پایان رسیده است.' })
res.status(403).json({ message: freeResult.message })
}
} else {
const response = await axios.post(
@@ -721,16 +741,25 @@ const republishAdvertisingPaymentWeb = async (req, res) => {
const price = await getAdvertisingPriceFromDatabase(itemName) // Get price from database
const advertisingId = req.body.advertisingId // Get project ID from request body
const showDiscount = req.body.showDiscount
// IDOR: قبلاً هیچ‌جا چک نمی‌شد که این بیلبورد واقعاً متعلق به همین کاربرِ
// احرازهویت‌شده‌ست — یه advertisingId دلخواه کافی بود تا کاربرِ دیگه‌ای پرداخت
// کنه ولی بیلبوردِ یه کاربرِ کاملاً متفاوت تایید/پرداخت‌شده بشه (رایگان بود، فقط
// با مصرفِ سهمیه‌ی رایگانِ همون کاربر هم ممکن بود)
const advertisingForOwnerCheck = await AdvertisingModel.findById(advertisingId).select('creator_id')
if (!advertisingForOwnerCheck) {
return res.status(404).json({ message: 'بیلبورد یافت نشد' })
}
if (String(advertisingForOwnerCheck.creator_id) !== String(userId)) {
return res.status(403).json({ message: 'دسترسی به این بیلبورد ندارید' })
}
// Save project ID for later use in callback URL
req.session.advertisingId = advertisingId
const item = await AdvertisingTypeModel.findOne({ name: itemName })
const user = await UserModel.findById(userId)
if (item.name === 'free' && item.price === 0) {
if (canUseFreeBillboard(user)) {
await consumeFreeBillboard(user)
// updateOne + $inc به‌جای user.save() — رجوع کنید به توضیح مشابه در initiateOfferPaymentWeb
await UserModel.updateOne({ _id: userId }, { $inc: { free_billboard_count: 1 } })
const freeResult = await tryConsumeFreeBillboard(UserModel, userId)
if (freeResult.ok) {
const project = await AdvertisingModel.findById(advertisingId)
if (!project) {
res.status(404).send('Advertising not found')
@@ -741,7 +770,7 @@ const republishAdvertisingPaymentWeb = async (req, res) => {
await project.save()
res.status(200).json({ message: 'بیلبورد رایگان با موفقیت ایجاد شد', advertisingId, type: 'free' })
} else {
res.status(403).json({ message: 'سقف ۲۰۰ بیلبورد رایگان شما به پایان رسیده است.' })
res.status(403).json({ message: freeResult.message })
}
} else {
const response = await axios.post(