QAZAQ CARGO — ЭЦҚ арқылы кіру
Қонақ

🚛 QAZAQ CARGO

Қазақстан және халықаралық бағыттар бойынша транспорт пен жүк тасымалдаушыларды байланыстыратын онлайн платформа.

🔐 ЭЦҚ арқылы қауіпсіз кіру

Қазақстанның Ұлттық куәландырушы орталығының ЭЦҚ-сын пайдаланып жүйеге кіріңіз. AUTH_RSA кілті арқылы аутентификация жасауға болады.

NCALayer орнату
Барлық транспорт
0
Одобрено
0
Пайдаланушылар
0
Күтуде
0
немесе


Аккаунтыңыз жоқ па?

📝 Тіркелу

🔎 Транспорт іздеу

➕ Транспорт жариялау

👤 Жеке кабинет


⛔ Доступ жоқ

QAZAQ CARGO

Жүк және транспорт биржасы
from pathlib import Path import zipfile, textwrap, os, json root=Path("/mnt/data/qazaq-cargo") (root/"public").mkdir(parents=True,exist_ok=True) (root/"src").mkdir(exist_ok=True) (root/"package.json").write_text("""{ "name":"qazaq-cargo", "version":"1.0.0", "private":true, "scripts":{"start":"node server.js","dev":"node --watch server.js"}, "dependencies":{ "dotenv":"^16.4.7", "express":"^5.1.0", "firebase-admin":"^13.5.0", "express-rate-limit":"^8.0.1" } }""",encoding="utf-8") (root/".env.example").write_text("""# SERVER PORT=3000 NODE_ENV=development # WhatsApp Cloud API WHATSAPP_ACCESS_TOKEN=PASTE_META_ACCESS_TOKEN_HERE WHATSAPP_PHONE_NUMBER_ID=PASTE_PHONE_NUMBER_ID_HERE WHATSAPP_API_VERSION=v23.0 WHATSAPP_SENDER_NUMBER=+77783727777 # OTP OTP_TTL_SECONDS=300 OTP_COOLDOWN_SECONDS=60 # Firebase Admin # Recommended: put the JSON service account file outside public/ GOOGLE_APPLICATION_CREDENTIALS=./serviceAccountKey.json FIREBASE_PROJECT_ID=PASTE_FIREBASE_PROJECT_ID_HERE # First admin phone, digits only, e.g. 77783727777 ADMIN_PHONE=77783727777 """,encoding="utf-8") (root/"serviceAccountKey.json.example").write_text("""{ "type": "service_account", "project_id": "YOUR_PROJECT_ID", "private_key_id": "YOUR_PRIVATE_KEY_ID", "private_key": "-----BEGIN PRIVATE KEY-----\\\\nPASTE_PRIVATE_KEY\\\\n-----END PRIVATE KEY-----\\\\n", "client_email": "firebase-adminsdk-xxxxx@YOUR_PROJECT_ID.iam.gserviceaccount.com", "client_id": "YOUR_CLIENT_ID", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "PASTE_CLIENT_CERT_URL" }""",encoding="utf-8") (root/"server.js").write_text(r"""require("dotenv").config(); const path=require("path"); const crypto=require("crypto"); const express=require("express"); const rateLimit=require("express-rate-limit"); const {initializeApp,cert,getApps}=require("firebase-admin/app"); const {getFirestore,FieldValue}=require("firebase-admin/firestore"); const app=express(); const PORT=process.env.PORT||3000; app.use(express.json({limit:"100kb"})); app.use(express.static(path.join(__dirname,"public"))); function initFirebase(){ if(getApps().length)return getFirestore(); const opts={projectId:process.env.FIREBASE_PROJECT_ID}; if(process.env.GOOGLE_APPLICATION_CREDENTIALS){ const fs=require("fs"); const f=path.resolve(process.env.GOOGLE_APPLICATION_CREDENTIALS); if(fs.existsSync(f)) opts.credential=cert(require(f)); } initializeApp(opts); return getFirestore(); } let db; try{db=initFirebase()}catch(e){console.error("Firebase init error:",e.message)} const otpStore=new Map(); const sessions=new Map(); const sendLimiter=rateLimit({windowMs:15*60*1000,max:5,standardHeaders:true,legacyHeaders:false}); const verifyLimiter=rateLimit({windowMs:15*60*1000,max:15,standardHeaders:true,legacyHeaders:false}); function digits(phone){return String(phone||"").replace(/\D/g,"").replace(/^8/,"7")} function validPhone(p){return /^7\d{10}$/.test(p)} function token(){return crypto.randomBytes(32).toString("hex")} function requireDb(res){if(!db){res.status(503).json({error:"Firebase not configured"});return false}return true} function auth(req,res,next){ const t=(req.headers.authorization||"").replace(/^Bearer\s+/,""); const s=sessions.get(t); if(!s)return res.status(401).json({error:"Unauthorized"}); req.user=s;req.sessionToken=t;next(); } function admin(req,res,next){if(req.user.role!=="admin"&&req.user.role!=="moderator")return res.status(403).json({error:"Admin only"});next()} async function sendWhatsAppText(to,text){ const url=`https://graph.facebook.com/${process.env.WHATSAPP_API_VERSION||"v23.0"}/${process.env.WHATSAPP_PHONE_NUMBER_ID}/messages`; const r=await fetch(url,{method:"POST",headers:{ "Authorization":`Bearer ${process.env.WHATSAPP_ACCESS_TOKEN}`, "Content-Type":"application/json" },body:JSON.stringify({messaging_product:"whatsapp",to,type:"text",text:{preview_url:false,body:text}})}); const data=await r.json(); if(!r.ok)throw new Error(data?.error?.message||"WhatsApp API error"); return data; } app.get("/api/health",(req,res)=>res.json({ ok:true, firebase:!!db, whatsappConfigured:!!(process.env.WHATSAPP_ACCESS_TOKEN&&process.env.WHATSAPP_PHONE_NUMBER_ID), sender:process.env.WHATSAPP_SENDER_NUMBER||null })); app.post("/api/auth/send-otp",sendLimiter,async(req,res)=>{ const phone=digits(req.body.phone); if(!validPhone(phone))return res.status(400).json({error:"Введите корректный номер Казахстана, например +7 778 372 77 77"}); const old=otpStore.get(phone); if(old&&Date.now()-old.created{ if(!requireDb(res))return; const phone=digits(req.body.phone),code=String(req.body.code||"").trim(),x=otpStore.get(phone); if(!validPhone(phone)||!x)return res.status(400).json({error:"Код не найден или истёк"}); if(Date.now()-x.created>Number(process.env.OTP_TTL_SECONDS||300)*1000)return res.status(400).json({error:"Код истёк"}); if(x.attempts>=5)return res.status(429).json({error:"Слишком много попыток"}); x.attempts++; const hash=crypto.createHash("sha256").update(code).digest("hex"); if(hash!==x.hash)return res.status(400).json({error:"Неверный код"}); otpStore.delete(phone); const ref=db.collection("users").doc(phone); const snap=await ref.get(); let user=snap.exists?snap.data():{ id:phone,phone,name:"",company:"",iin:"", role:phone===digits(process.env.ADMIN_PHONE)?"admin":"user", createdAt:FieldValue.serverTimestamp() }; await ref.set({...user,lastLoginAt:FieldValue.serverTimestamp()},{merge:true}); const t=token();sessions.set(t,{id:phone,phone,role:user.role,name:user.name,company:user.company||""}); res.json({ok:true,token:t,user:{id:phone,phone,role:user.role,name:user.name,company:user.company||""},needsProfile:!user.name}); }); app.put("/api/me",auth,async(req,res)=>{ if(!requireDb(res))return; const data={name:String(req.body.name||"").trim(),company:String(req.body.company||"").trim(),iin:String(req.body.iin||"").trim()}; if(!data.name)return res.status(400).json({error:"Имя обязательно"}); await db.collection("users").doc(req.user.id).set(data,{merge:true}); Object.assign(req.user,data); res.json({ok:true,user:req.user}); }); app.post("/api/transports",auth,async(req,res)=>{ if(!requireDb(res))return; const b=req.body; if(!b.from||!b.to||!b.date||!b.body||!b.weight)return res.status(400).json({error:"Заполните обязательные поля"}); const ref=await db.collection("transports").add({ from:String(b.from),to:String(b.to),date:String(b.date),body:String(b.body), weight:Number(b.weight),volume:Number(b.volume||0),number:String(b.number||""), price:Number(b.price||0),currency:String(b.currency||"тенге"), phone:String(b.phone||req.user.phone),gps:String(b.gps||"Жоқ"), description:String(b.description||""),userId:req.user.id,userName:req.user.name||"", status:"pending",createdAt:FieldValue.serverTimestamp() }); res.json({ok:true,id:ref.id}); }); app.get("/api/transports",async(req,res)=>{ if(!requireDb(res))return; let q=db.collection("transports"); if(req.query.status)q=q.where("status","==",String(req.query.status)); const snap=await q.limit(200).get(); const arr=snap.docs.map(d=>({id:d.id,...d.data()})); res.json({ok:true,items:arr}); }); app.get("/api/my-transports",auth,async(req,res)=>{ if(!requireDb(res))return; const snap=await db.collection("transports").where("userId","==",req.user.id).limit(100).get(); res.json({ok:true,items:snap.docs.map(d=>({id:d.id,...d.data()}))}); }); app.patch("/api/admin/transports/:id",auth,admin,async(req,res)=>{ if(!requireDb(res))return; const status=String(req.body.status||""); if(!["approved","rejected","pending"].includes(status))return res.status(400).json({error:"Invalid status"}); await db.collection("transports").doc(req.params.id).update({status,moderatedBy:req.user.id,moderatedAt:FieldValue.serverTimestamp()}); res.json({ok:true}); }); app.get("/api/admin/users",auth,admin,async(req,res)=>{ if(!requireDb(res))return; const snap=await db.collection("users").limit(500).get(); res.json({ok:true,items:snap.docs.map(d=>({id:d.id,...d.data()}))}); }); app.post("/api/logout",auth,(req,res)=>{sessions.delete(req.sessionToken);res.json({ok:true})}); app.get("*",(req,res)=>res.sendFile(path.join(__dirname,"public","index.html"))); app.listen(PORT,()=>console.log(`QAZAQ CARGO http://localhost:${PORT}`)); """,encoding="utf-8") # Simple frontend (root/"public/index.html").write_text(r""" QAZAQ CARGO
Қонақ

🚛 QAZAQ CARGO

Жүк және транспорт тасымалдаушыларына арналған платформа.

💬 WhatsApp арқылы тіркелу

ЭЦҚ/NCALayer жоқ. OTP коды тікелей WhatsApp-қа жіберіледі.

📱 WhatsApp OTP

🔎 Транспорт

➕ Транспорт қосу

Алдымен WhatsApp арқылы кіріңіз.

👤 Кабинет

🛠 Admin Panel

МаршрутДатаКузовАвторСтатусӘрекет
""",encoding="utf-8") (root/"README.md").write_text("""# QAZAQ CARGO — WhatsApp OTP + Firebase/Firestore ## 1. Орнату ```bash npm install copy .env.example .env