This commit is contained in:
2025-04-30 13:11:35 +03:00
parent c8f3c9801f
commit cda54b1e95
60 changed files with 1054 additions and 651 deletions

BIN
backend/_old/backend.zip Normal file

Binary file not shown.

BIN
backend/api (2).xls Normal file

Binary file not shown.

View File

@@ -15,7 +15,7 @@ BigInt.prototype.toJSON = function () {
return Number(this)
}
app.use((req, res, next) => {
/* app.use((req, res, next) => {
if(!(req.body instanceof Object))
return next()
@@ -26,29 +26,17 @@ app.use((req, res, next) => {
.map(key => req.body[key] = escapeHtml(req.body[key]))
next()
})
}) */
// cors
app.use((req, res, next) => {
res.set({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Headers': 'Accept,Accept-Language,Content-Language,Content-Type,Authorization,Cookie,X-Requested-With,Origin,Host',
'Access-Control-Allow-Credentials': true
})
return req.method == 'OPTIONS' ? res.status(200).json({success: true}) : next()
})
app.post('(/api/admin/customer/login|/api/miniapp/user/login)', (req, res, next) => {
app.post('(/api/admin/auth/telegram|/api/miniapp/auth)', (req, res, next) => {
const data = Object.assign({}, req.query)
delete data.hash
const hash = req.query?.hash
const BOT_TOKEN = '7236504417:AAGVaodw3cRwGlf-jAhwnYb51OHaXcgpW8k'
const dataCheckString = Object.keys(data).sort().map((key) => `${key}=${data[key]}`).join("\n")
const secretKey = crypto.createHmac("sha256", "WebAppData").update(BOT_TOKEN).digest()
const hmac = crypto.createHmac("sha256", secretKey).update(dataCheckString).digest("hex")
const dataCheckString = Object.keys(data).sort().map((key) => `${key}=${data[key]}`).join('\n')
const secretKey = crypto.createHmac('sha256', 'WebAppData').update(BOT_TOKEN).digest()
const hmac = crypto.createHmac('sha256', secretKey).update(dataCheckString).digest('hex')
const timeDiff = Date.now() / 1000 - data.auth_date
@@ -73,14 +61,9 @@ app.use((err, req, res, next) => {
console.error(`Error for ${req.path}: ${err}`)
let message, code
//if (err.code == 'SQLITE_ERROR' || err.code == 'SQLITE_CONSTRAINT_CHECK') {
// message = 'DATABASE_ERROR'
//code = err.code == 'SQLITE_CONSTRAINT_CHECK' ? 400 : 500
//} else {
[message, code = 500] = err.message.split('::')
//}
[message, code = 500] = err.message.split('::')
res.status(res.statusCode == 200 ? 500 : res.statusCode).json({success: false, error: { message, code}})
res.status(code).json({success: false, error: { message, code}})
})
app.use(express.static('public'))

View File

@@ -15,11 +15,10 @@ const upload = multer({
})
const sessions = {}
const emailCache = {} // key = email, value = code
app.use((req, res, next) => {
if (req.path == '/customer/login' ||
req.path == '/customer/register' ||
req.path == '/customer/activate')
if (req.path == '/auth/email' || req.path == '/auth/telegram' || req.path == '/auth/register' || req.path == '/auth/logout')
return next()
const asid = req.query.asid || req.cookies.asid
@@ -31,96 +30,104 @@ app.use((req, res, next) => {
next()
})
// CUSTOMER
app.post('/customer/login', (req, res, next) => {
// AUTH
function createSession(req, res, customer_id) {
if (!customer_id)
throw Error('AUTH_ERROR::500')
res.locals.customer_id = customer_id
const asid = crypto.randomBytes(64).toString('hex')
req.session = sessions[asid] = {asid, customer_id }
res.setHeader('Set-Cookie', [`asid=${asid};httpOnly;path=/api/admin`])
}
app.post('/auth/email', (req, res, next) => {
res.locals.email = req.body?.email
res.locals.password = req.body?.password
let customer_id = db
.prepare(`
select id
from customers
where is_active = 1 and (
email is not null and email = :email and password is not null and password = :password or
email is null and password is null and telegram_user_id = :telegram_id
)
`)
const customer_id = db
.prepare(`select id from customers where is_blocked = 0 and email = :email and password is not null and password = :password `)
.pluck(true)
.get(res.locals)
if (!customer_id && !res.locals.email && !res.locals.password) {
customer_id = db
.prepare(`insert into customers (telegram_user_id, is_active) values (:telegram_id, 1) returning id`)
.safeIntegers(true)
.pluck(true)
.get(res.locals)
}
if (!customer_id)
throw Error('AUTH_ERROR::401')
res.locals.customer_id = customer_id
db
.prepare(`update customers set telegram_user_id = :telegram_id where id = :customer_id and email is not null`)
.run(res.locals)
const asid = crypto.randomBytes(64).toString('hex')
req.session = sessions[asid] = {asid, customer_id }
res.setHeader('Set-Cookie', [`asid=${asid};httpOnly;path=/api/admin`])
createSession(req, res, customer_id)
res.status(200).json({success: true})
})
app.get('/customer/logout', (req, res, next) => {
delete sessions[req.session.asid]
res.setHeader('Set-Cookie', [`asid=; expired; httpOnly`])
app.post('/auth/telegram', (req, res, next) => {
let customer_id = db
.prepare(`select id from customers where is_blocked = 0 and telegram_id = :telegram_id`)
.pluck(true)
.get(res.locals) || db
.prepare(`replace into customers (telegram_id, is_blocked) values (:telegram_id, 0) returning id`)
.pluck(true)
.get(res.locals)
createSession(req, res, customer_id)
res.status(200).json({success: true})
})
app.post('/customer/register', (req, res, next) => {
const email = String(req.body.email).trim()
const password = String(req.body.password).trim()
app.get('/auth/logout', (req, res, next) => {
if (req.session?.asid)
delete sessions[req.session.asid]
res.setHeader('Set-Cookie', [`asid=; expired; httpOnly;path=/api/admin`])
res.status(200).json({success: true})
})
const validateEmail = email => String(email).toLowerCase().match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)
if (!validateEmail(email))
app.post('/auth/register', (req, res, next) => {
const email = String(req.body.email ?? '').trim()
const code = String(req.body.code ?? '').trim()
const password = String(req.body.password ?? '').trim()
if (email) {
const validateEmail = email => String(email).toLowerCase().match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)
if (!validateEmail(email))
throw Error('INCORRECT_EMAIL::400')
if (!password)
throw Error('EMPTY_PASSWORD::400')
const row = db
const customer_id = db
.prepare('select id from customers where email = :email')
.run({email})
if (row)
throw Error('DUPLICATE_EMAIL::400')
.pluck(true)
.get({email})
if (customer_id)
throw Error('USED_EMAIL::400')
}
if (email && !code) {
const code = Math.random().toString().substr(2, 4)
emailCache[email] = code
// To-Do: send email
console.log(`${email} => ${code}`)
}
if (email && code && !password) {
if (emailCache[email] != code)
throw Error('INCORRECT_CODE::400')
}
if (email && code && password) {
if (password.length < 8)
throw Error('INCORRECT_PASSWORD::400')
db
.prepare('insert into customers (email, password, is_blocked) values (:email, :password, 0)')
.run({email, password})
}
res.status(200).json({success: true})
})
const key = crypto.randomBytes(32).toString('hex')
const info = db
.prepare('insert into customers (email, password, activation_key) values (:email, :password, :key)')
.run({email, password, key})
// To-Do: SEND MAIL
console.log(`http://127.0.0.1:3000/api/customer/activate?key=${key}`)
res.status(200).json({success: true, data: key})
})
app.get('/customer/activate', (req, res, next) => {
const row = db
.prepare('update customers set is_active = 1 where activation_key = :key returning id')
.get({key: req.query.key})
if (!row || !row.id)
throw Error('BAD_ACTIVATION_KEY::400')
res.status(200).json({success: true})
})
// CUSTOMER
app.get('/customer/profile', (req, res, next) => {
const row = db
.prepare(`
select id, name, email, plan, coalesce(json_balance, '{}') json_balance, coalesce(json_company, '{}') json_company, upload_group_id
from customers
where id = :customer_id and is_active = 1
where id = :customer_id
`)
.get(res.locals)

View File

@@ -10,8 +10,9 @@ const { NewMessage } = require('telegram/events')
const { Button } = require('telegram/tl/custom/button')
const { CustomFile } = require('telegram/client/uploads')
// const session = new StringSession('1AgAOMTQ5LjE1NC4xNjcuNTABuxdIxmjimA0hmWpdrlZ4Fo7uoIGU4Bu9+G5QprS6zdtyeMfcssWEZp0doLRX/20MomQyF4Opsos0El0Ifj5aiNgg01z8khMLMeT98jS+1U/sh32p3GxZfxyXSxX1bD0NLRaXnqVyNNswYqRZPhboT28NMjDqwlz0nrW9rge+QMJDL7jIkXgSs+cmJBINiqsEI8jWjXmc8TU/17gngtjUHRf5kRM4y5gsNC4O8cF5lcHRx0G/U5ZVihTID8ItQ6EdEHjz6e4XErbVOJ81PfYkqEoPXVvkEmRM0/VbvCzFfixfas4Vzczfn98OHLd8P2MXcgokZ2rppvIV3fQXOHxJbA0=')
const session = new StringSession('')
//const session = new StringSession('1AgAOMTQ5LjE1NC4xNjcuNTABu2OaFuD5Oyi5wGck+n5ldAfshzYfwlWee+OUxYBvFzlKAdW11Hsndu1SJBLUnKjP8sTJEPbLwdqANBhBXmQMghLVAblwK6TxLfsWxy2zf/HGLeNXohhrsep0hBxu9imyHV6OI6gQG+c5qaGkzjZrz0AcS4ut0xy99XrXgjiNfnjeMX7a0mOk6IK9iKdwbX9kXTfclFLVppiBGXolYJjVb2E57tk4+7RncIVyw+Fxn0NZfnhEfHJZly6j03arZOeM5VYl9ul8+3lJDD+KJJHeMgImmYjmcFcF3CbtkhPuTSPnWKtCnm2sRzepn5VFfoG6zgYff04fBdKGvHAai+wQSOY=')
const session = new StringSession('1AgAOMTQ5LjE1NC4xNjcuNTEBuzSgmBQR5/m8M8cyOnsLCIOkYQJTizJoJRZiPKK+eBjMuodc0JuKQwzeWBRJI/c6YxaBHvokpngf5kr57uly+meSPPlFq6MyoSSQDbEJ3VAAWJu+/ALN0ickE92RjRfM5Kw6DimC9FXuMgJJsoUHtk/i+ZGXy9JB+q67G0yy8NvFIuWpFHJDkwmi0qTlTgJ5UOm4PYkV01iNUcV5siaWFVTTLsetHtBUdMOzg5WjjvuOyYV/MIx+z7ynhvF3DxLPCugxqhCvZ/RW+0vldrTX5TZ0BzIDk2eNFQjRORJcZo6upwvH7aZYStV4DxhIi1dEYu5gyvnt4vkbR5kuvE/GqO0=')
let client
@@ -493,12 +494,19 @@ async function onNewUserMessage (msg) {
updateUser(userId, user)
await updateUserPhoto (userId, user)
const appButton = new Api.KeyboardButtonWebView({
text: "Open Mini-App", // Текст на кнопке
url: "https://h5sj0gpz-3000.euw.devtunnels.ms/", // URL вашего Mini-App (HTTPS!)
});
const inputPeer = new Api.InputPeerUser({userId: tgUserId, accessHash: user.accessHash.value})
const resultBtn = await client.sendMessage(inputPeer, {
message: 'Сообщение от бота',
buttons: client.buildReplyMarkup([
[Button.url('Админка', 'https://t.me/ready_or_not_2025_bot/userapp?startapp=admin')],
[Button.url('Пользователь', 'https://t.me/ready_or_not_2025_bot/userapp?startapp=user')]
[Button.url('Пользователь', 'https://t.me/ready_or_not_2025_bot/userapp?startapp=user')],
[appButton]
])
})
} catch (err) {
@@ -560,6 +568,7 @@ class Bot extends EventEmitter {
})
await client.start({botAuthToken})
console.log('SID: ', session.save())
}
async uploadDocument(projectId, fileName, mime, data, parentType, parentId, publishedBy) {

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -5,11 +5,10 @@ create table if not exists customers (
name text check(name is null or trim(name) <> '' and length(name) < 256),
email text check(email is null or trim(email) <> '' and length(email) < 128),
password text check(password is null or length(password) > 7 and length(password) < 64),
telegram_user_id integer,
telegram_id integer,
plan integer,
json_balance text default '{}',
activation_key text,
is_active integer default 0,
is_blocked integer default 0,
json_company text default '{}',
upload_group_id integer,
json_backup_server text default '{}',

1
backend/letsgo.bat Normal file
View File

@@ -0,0 +1 @@
node app

View File

@@ -392,9 +392,9 @@
}
},
"node_modules/detect-libc": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
"license": "Apache-2.0",
"engines": {
"node": ">=8"
@@ -1169,9 +1169,9 @@
}
},
"node_modules/nodemailer": {
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz",
"integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==",
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.1.tgz",
"integrity": "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==",
"license": "MIT-0",
"engines": {
"node": ">=6.0.0"

View File

@@ -8,7 +8,7 @@
<meta name="MobileOptimized" content="176" />
<meta name="HandheldFriendly" content="True" />
<meta name="robots" content="noindex,nofollow" />
<script src="https://telegram.org/js/telegram-web-app.js?56"></script>
<script src="https://telegram.org/js/telegram-web-app.js?57"></script>
<title></title>
<style>
*[hidden] {display: none;}
@@ -22,7 +22,7 @@
<body>
<div id = "adminapp" hidden>
<b>Админка</b>
<b>Админка2</b>
<div id = "settings" class = "block">
<b>Настройки</b><br>
<input id = "name" type = "text" placeholder = "Name">
@@ -282,18 +282,24 @@ $adminapp.querySelector('#companies #add-company').addEventListener('click', asy
}).catch(alert)
})
try {
(async () => {
window.addEventListener('load', async (event) => {
const startParams = (Telegram.WebApp.initDataUnsafe.start_param || '').split('_')
const isAdmin = startParams[0] == 'admin'
//const isAdmin = startParams[0] == 'admin'
const isAdmin = true
const $app = isAdmin ? $adminapp : $miniapp
$app.hidden = false
const login_url = isAdmin ? '/api/admin/customer/login?' : '/api/miniapp/user/login?'
const login_url = isAdmin ? '/api/admin/auth/telegram?' : '/api/miniapp/auth?'
await Telegram.WebApp.ready()
console.log(Telegram)
if (Telegram.WebApp.initData == '') {
alert('NO INIT DATA')
return 0
}
console.log('TG', Telegram)
const login = await fetch(login_url + Telegram.WebApp.initData, {method: 'POST'}).then(res => res.json())
console.log(login)
@@ -324,12 +330,8 @@ try {
if (startParams[1])
alert('Группа на проекте ' + startParams[1])
}
})()
})
} catch (err) {
alert(err)
}
</script>