This commit is contained in:
payacom
2026-08-31 20:45:41 +03:30
parent fa9f23c61d
commit 3f416a7a60
367 changed files with 621895 additions and 6443 deletions

View File

@@ -0,0 +1,57 @@
const fs = require('fs')
const path = require('path')
const root = path.join(__dirname, '..')
const { isE2eeEnvelope, opaquePreview } = require('../utils/e2ee')
const checks = []
const env = JSON.stringify({ v: 1, e2ee: true, iv: 'x', ciphertext: 'y' })
checks.push(['envelope detect', isE2eeEnvelope(env) === true])
checks.push(['opaque', opaquePreview(env).includes('رمزنگاری')])
checks.push(['plain', opaquePreview('سلام دنیا').includes('سلام')])
const idx = fs.readFileSync(path.join(root, 'index.js'), 'utf8')
checks.push(['socket jwt binding', idx.includes('socket.data.userId') && idx.includes('jwt.verify')])
checks.push(['sms disabled', idx.includes('status(410)')])
const routes = fs.readFileSync(path.join(root, 'routes/index.js'), 'utf8')
checks.push(['panel adminAuth', routes.includes("panel/users', [adminAuth]")])
const profile = fs.readFileSync(
path.join(root, 'controllers/application/profile/profileController.js'),
'utf8'
)
checks.push([
'profile strips secrets',
!profile.includes('password: user.password') && profile.includes('e2ee_public_key')
])
const userModel = fs.readFileSync(path.join(root, 'models/UserModel.js'), 'utf8')
checks.push(['user e2ee field', userModel.includes('e2ee_public_key')])
const roomModel = fs.readFileSync(path.join(root, 'models/ChatRoomModel.js'), 'utf8')
checks.push([
'room e2ee fields',
roomModel.includes('e2ee_wrapped_keys') && roomModel.includes('e2ee_enabled')
])
const frontRoot = path.join(root, '../modstagram-next/src/lib/e2ee')
const frontOk = ['dm.ts', 'room.ts', 'keys.ts', 'crypto.ts', 'envelope.ts'].every((f) =>
fs.existsSync(path.join(frontRoot, f))
)
checks.push(['front e2ee lib', frontOk])
const roomCtrl = fs.readFileSync(
path.join(root, 'controllers/application/chatRooms/chatRoomController.js'),
'utf8'
)
checks.push(['room membership gate', roomCtrl.includes('NOT_A_MEMBER')])
checks.push([
'room e2ee APIs',
roomCtrl.includes('getRoomE2eeKeys') && roomCtrl.includes('putRoomE2eeKeys')
])
for (const [name, ok] of checks) {
console.log(`${ok ? 'OK' : 'FAIL'} ${name}`)
}
if (checks.some(([, ok]) => !ok)) process.exit(1)
console.log('ALL CHECKS PASSED')

View File

@@ -1,4 +1,4 @@
# فرانت — modstagram.com → Next.js port 3001
# فرانت — modstagram.com → Next.js (PM2 / npm start روی پورت 3004)
# مسیر: /etc/nginx/sites-available/modstagram.com
server {
@@ -10,7 +10,7 @@ server {
}
location / {
proxy_pass http://127.0.0.1:3001;
proxy_pass http://127.0.0.1:3004;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

View File

@@ -0,0 +1,33 @@
/**
* One-time migration: recalculate rate (total stars) and user_score (average)
* for all users. Run from modstagram-back:
* node scripts/recalculateAllUserRatings.js
*/
require('dotenv').config()
const mongoose = require('mongoose')
const UserModel = require('../models/UserModel')
const { recalculateUserRating } = require('../utils/commentRating')
async function main() {
const uri = process.env.DATABASE_URL || process.env.MONGODB_URI || process.env.DB_URL
if (!uri) {
console.error('DATABASE_URL (or MONGODB_URI/DB_URL) required')
process.exit(1)
}
await mongoose.connect(uri)
const users = await UserModel.find({}, '_id').lean()
console.log(`Recalculating ${users.length} users...`)
for (const user of users) {
await recalculateUserRating(user._id)
}
console.log('Done.')
await mongoose.disconnect()
}
main().catch((err) => {
console.error(err)
process.exit(1)
})

28
scripts/seedGeoData.js Normal file
View File

@@ -0,0 +1,28 @@
/**
* Manual/CI trigger for the same geo seed logic that also runs automatically
* on every backend boot (utils/ensureGeoData.js, wired in boot/mongo.js) —
* kept as a single shared implementation so the two paths never drift.
*
* Run from modstagram-back:
* node scripts/seedGeoData.js
*/
require('dotenv').config()
const mongoose = require('mongoose')
const { ensureGeoData } = require('../utils/ensureGeoData')
async function main() {
const uri = process.env.DATABASE_URL
if (!uri) {
console.error('DATABASE_URL is required (check .env)')
process.exit(1)
}
await mongoose.connect(uri, { authSource: 'admin' })
await ensureGeoData(true)
await mongoose.disconnect()
}
main().catch((err) => {
console.error(err)
process.exit(1)
})

View File

@@ -78,7 +78,7 @@ certbot --nginx --non-interactive --agree-tos --email "$ADMIN_EMAIL" \
-d modstagram.com -d www.modstagram.com || echo " WARN: modstagram.com SSL failed"
certbot --nginx --non-interactive --agree-tos --email "$ADMIN_EMAIL" \
-d api.modstagram.com || echo " WARN: api SSL failed"
-d api.modstagram.com -d app.modstagram.com || echo " WARN: api SSL failed"
certbot --nginx --non-interactive --agree-tos --email "$ADMIN_EMAIL" \
-d panel.modstagram.com || echo " WARN: panel SSL failed"

87
scripts/verify-backend.js Normal file
View File

@@ -0,0 +1,87 @@
#!/usr/bin/env node
/**
* Run from modstagram-back root on the server:
* node scripts/verify-backend.js
*/
const fs = require('fs')
const path = require('path')
const { execSync } = require('child_process')
const root = path.join(__dirname, '..')
let failed = false
function fail (message) {
console.error('FAIL:', message)
failed = true
}
function ok (message) {
console.log('OK:', message)
}
function walkJs (dir, out = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
if (entry.name === 'node_modules' || entry.name === 'dist') continue
const full = path.join(dir, entry.name)
if (entry.isDirectory()) walkJs(full, out)
else if (entry.name.endsWith('.js')) out.push(full)
}
return out
}
console.log('Checking merge conflicts...')
const conflictPattern = /^<<<<<<<|^=======|^>>>>>>>/
for (const file of walkJs(root)) {
const firstLines = fs.readFileSync(file, 'utf8').split('\n').slice(0, 3)
if (firstLines.some((line) => conflictPattern.test(line.trim()))) {
fail(`merge conflict marker in ${path.relative(root, file)}`)
}
}
if (!failed) ok('no merge conflict markers')
console.log('Syntax check...')
const critical = [
'index.js',
'routes/index.js',
'controllers/application/users/getUserController.js',
'controllers/application/projects/getProjectController.js',
'controllers/application/stories/storyController.js',
'controllers/panel/projects/projectController.js'
]
for (const rel of critical) {
try {
execSync(`node --check "${path.join(root, rel)}"`, { stdio: 'pipe' })
ok(rel)
} catch {
fail(`syntax error in ${rel}`)
}
}
console.log('Loading routes...')
try {
process.chdir(root)
require('../routes/index.js')
ok('routes/index.js loaded')
} catch (error) {
fail(`routes load: ${error.message}`)
}
console.log('Loading getUserController...')
try {
const mod = require('../controllers/application/users/getUserController.js')
if (typeof mod.getPostsWeb !== 'function') {
fail('getPostsWeb export missing')
} else {
ok('getPostsWeb export')
}
} catch (error) {
fail(`getUserController: ${error.message}`)
}
if (failed) {
console.error('\nBackend verification FAILED')
process.exit(1)
}
console.log('\nBackend verification PASSED')
process.exit(0)