commit 6d394e27568f9dc2a0fe9e05cb37ece477eacbc5 Author: wy Date: Mon Jun 6 09:18:26 2022 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..096746c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/node_modules/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b595980 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# node-panel \ No newline at end of file diff --git a/app.js b/app.js new file mode 100644 index 0000000..4f4b2a0 --- /dev/null +++ b/app.js @@ -0,0 +1,70 @@ +var createError = require('http-errors'); +var express = require('express'); +var path = require('path'); +var logger = require('morgan'); +var serveStatic = require('serve-static') +var favicon = require('serve-favicon') + + + +var app = express(); + +// view engine setup +//app.engine('html', require('express-art-template')); + +app.set('views', path.join(__dirname, 'views')); +//app.set('view engine', 'html'); + +app.use(logger('dev')); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); + +// app.use('/static', express.static(path.join(__dirname, 'public')),{ +// etag: false +// }) +app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))) +app.use('/static', serveStatic(path.join(__dirname, 'public'),{ + etag: false +})) +app.use(function(req, res, next) { + req.headers['if-none-match'] = 'no-match-for-this'; + next(); +}); + +//路由,前台 +let indexRouter = require('./routes/index'); + +app.use('/', indexRouter); + +//路由,后台 +let muNodesRouter=require('./routes/mu/nodes.js'); +app.use('/mod_mu/nodes', muNodesRouter); + +let muUsersRouter=require('./routes/mu/users.js'); +app.use('/mod_mu/users', muUsersRouter); + + +let muFuncRouter=require('./routes/mu/func.js'); +app.use('/mod_mu/func', muFuncRouter); + + +// catch 404 and forward to error handler +app.use(function(req, res, next) { + if (req.path && !req.path.endsWith('.map')){ + next(createError(404)); + } +}); + +// error handler +app.use(function(err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + console.error(err.stack); + // render the error page + res.status(err.status || 500); + res.render('error'); +}); + + +module.exports = app; diff --git a/bin/www b/bin/www new file mode 100644 index 0000000..6a2065a --- /dev/null +++ b/bin/www @@ -0,0 +1,93 @@ + +const path = require('path'); +let envPath = path.join(__dirname, `../env.${process.env.NODE_ENV}`) +require('dotenv').config({ path: envPath }) +var app = require('../app'); +var debug = require('debug')("mybot:www"); +var http = require('http'); + + +/** + * Get port from environment and store in Express. + */ + +var port = normalizePort(process.env.PORT || '3000'); +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); + console.info("项目启动了", port) + //schedule.initSchedule(); + +} + diff --git a/package.json b/package.json new file mode 100644 index 0000000..31fcdb3 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "node-panel", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "dev": "node ./bin/www NODE_ENV=development", + "start": "set NODE_ENV=development&nodemon --delay 1.5 bin/www ", + "prd": "pm2 start bin/www", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "debug": "^4.3.4", + "dotenv": "^16.0.1", + "express": "^4.18.1", + "morgan": "^1.10.0", + "nodemon": "^2.0.16", + "serve-favicon": "^2.5.0", + "serve-static": "^1.15.0" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..b85f407 Binary files /dev/null and b/public/favicon.ico differ diff --git a/routes/index.js b/routes/index.js new file mode 100644 index 0000000..63edb80 --- /dev/null +++ b/routes/index.js @@ -0,0 +1,23 @@ +const express = require('express'); +const router = express.Router(); + + + + +router.get('/', function(req, res, next) { + + res.send({ + title: '自娱自乐', + user: { + name: 'Index', + tags: ['art', 'template', 'nodejs'] + } + }); +}); + + +router.post('/ding', function(req, res, next) { + res.send({state:'ok', msg:'发送成功'}) +}); + +module.exports = router; diff --git a/routes/mu/func.js b/routes/mu/func.js new file mode 100644 index 0000000..9009ad7 --- /dev/null +++ b/routes/mu/func.js @@ -0,0 +1,40 @@ +var express = require('express'); + +var router = express.Router(); + + +router.get('/detect_rules', function(req, res, next) { + + console.info('GET /func/detect_rules nodeId:', req.query.node_id) + + let thatData = [ + {"regex":"BitTorrent protocol","id":1}, + {"regex":"(api|ps|sv|offnavi|newvector|ulog\\.imap|newloc)(\\.map|)\\.(baidu|n\\.shifen)\\.com","id":2}, + {"regex":"(.+\\.|^)(360|so)\\.(cn|com)","id":3}, + {"regex":"(Subject|HELO|SMTP)","id":4}, + {"regex":"\\b(dafahao|minghui|dongtaiwang|epochtimes|ntdtv|falundafa|wujieliulan|qxbbs|tuidang|rfi)\\.(org|com|net|fr)","id":5}, + {"regex":"(torrent|\\.torrent|peer_id=|info_hash|get_peers|find_node|BitTorrent|announce_peer|announce\\.php\\?passkey=|Joker)","id":6}, + {"regex":"(^.*\\@)(guerrillamail|guerrillamailblock|sharklasers|grr|pokemail|spam4|bccto|chacuo|027168)\\.(info|biz|com|de|net|org|me|la)","id":7}, + {"regex":"(.?)(sandai0|XLLiveUD0)(.)","id":8}, + {"regex":"(.*\\.||)(guanjia\\.qq\\.com|qqpcmgr|QQPCMGR)","id":9}, + {"regex":"\\b(rising|kingsoft|duba|xindubawukong|jinshanduba)\\.(com|net|org)","id":10}, + {"regex":"(.*\\.||)(fast|cachefly|speedtest)\\.(cn|org|com|net|de)","id":11}, + {"regex":"\\b(pincong|mohu|wujieliulan|epochtimes|voachinese|bbc|nytimes|landofhope)\\.(rocks|com|tv)","id":16}, + {"regex":"netbox\\.ipip\\.net","id":17}, + {"regex":"\\b(paramount|warnermedia|viacomcbs)\\.(rocks|com|tv)","id":18} + ] + let result = {ret:1, data: thatData} + + console.info('GET /func/detect_rules result:', result) + res.send(result) +}); + + +// 上送节点状态 负载状态 +router.post('/:nodeId/info', function(req, res, next) { + console.info('POST /func//:nodeId/info nodeId:', req.params.nodeId) + res.send({ret:1, data: "ok"}) +}) + + +module.exports = router;//暴露模块 diff --git a/routes/mu/nodes.js b/routes/mu/nodes.js new file mode 100644 index 0000000..2af8bd6 --- /dev/null +++ b/routes/mu/nodes.js @@ -0,0 +1,87 @@ +var express = require('express'); + +var router = express.Router(); + + +router.get('/:nodeId/info', function(req, res, next) { + console.info('GET /:nodeId/info:', req.params.nodeId) + + let nodeData = {} + + // + //let ss = {"ret":1,"data":{"node_group":0,"server":"38.106.24.3;58080","node_speedlimit":0,"traffic_rate":1,"sort":1,"node_class":1,"type":"ss-panel-v3-mod_Uim","mu_only":1}} + // ss + if(req.params.nodeId == 1){ + let serverData = { + //"offset_port_user": "12345", //前端/订阅中下发的端口 + "offset_port_node": "58080", //节点服务器下发的端口 + //"server_user": "hk.domain.com", //前端/订阅中下发的服务器地址 + "mu_encryption": "aes-256-gcm", // `aes-128-gcm`, `aes-256-gcm`, `chacha20-ietf-poly1305`三者之一 + } + //nodeData = {"ret":1,"data":{"node_group":0,"server":"38.106.24.3;58080","node_speedlimit":0,"traffic_rate":1,"sort":1,"node_class":1,"type":"ss-panel-v3-mod_Uim","mu_only":1}} + nodeData = { + "node_group":0, + "node_class":1, + "node_speedlimit":0, + "traffic_rate":1, + "mu_only":1, + "sort":1, + "type":"mimi-panel", + "server":"8.106.24.3;58080", + "custom_config": serverData, + "version":"2021.11" + } + } else if (req.params.nodeId == 2){ // v2ray + let serverData = { + "offset_port_node": "58082", + "alter_id": "0", + "network": "tcp", + "security": "none", + } + //nodeData = {"ret":1,"data":{"node_group":0,"server":"38.106.24.3;58080","node_speedlimit":0,"traffic_rate":1,"sort":1,"node_class":1,"type":"ss-panel-v3-mod_Uim","mu_only":1}} + nodeData = { + "node_group":0, + "node_class":1, + "node_speedlimit":0, + "traffic_rate":1, + "mu_only":1, + "sort":1, + "type":"mimi-panel", + "server":"141.164.57.1;58082;0;tcp;;", + "custom_config": serverData, + "version":"2021.11" + } + } else if (req.params.nodeId == 3){ // trojan + let serverData = { + //"offset_port_user": 443, + "offset_port_node": "58083", + "host": "19.g1cdn.com" + } + nodeData = { + "node_group":0, + "node_class":1, + "node_speedlimit":0, + "traffic_rate":1, + "mu_only":1, + "sort":1, + "type":"mimi-panel", + "server":"38.106.24.200;port=4419|host=19.g1cdn.com", + "custom_config": serverData, + "version":"2021.11" + } + } + let result = {ret:1, data: nodeData} + console.info("GET /:nodeId/info:", result) + res.send(result) +}); + + +// 上送节点状态 负载状态 +router.post('/:nodeId/info', function(req, res, next) { + console.info("POST /:nodeId/info nodeId:", req.params.nodeId) + console.info("POST /:nodeId/info body:", req.body) + res.send({ret:1, data: "ok"}) +}) + + +module.exports = router;//暴露模块 diff --git a/routes/mu/users.js b/routes/mu/users.js new file mode 100644 index 0000000..ff168a1 --- /dev/null +++ b/routes/mu/users.js @@ -0,0 +1,103 @@ +var express = require('express'); + +var router = express.Router(); + + +router.get('/', function(req, res, next) { + console.info('GET /users/ nodeId:', req.query.node_id) + + let userData = [ + { + "is_multi_user": 2, + "method": "aes-256-gcm", + "d": 0, + "node_speedlimit": 100, + "node_connector": 2, + "disconnect_ip": "", + "forbidden_ip": "", + "forbidden_port": "", + "protocol_param": "", + "obfs_param": "", + "uuid": "b63abe71-01f9-3ee3-8992-ce16e7bdbf99", + "protocol": "auth_aes128_md5", + "obfs": "tls1.2_ticket_auth", + "port": 58080, + "passwd": "1_www.mimi.ooo", + "u": 0, + "id": 1, + "email": "1_1_www.mimi.ooo" + }, + { + "is_multi_user": 0, + "method": "aes-256-gcm", + "d": 260605780723, + "node_speedlimit": 500, + "node_connector": 14, + "disconnect_ip": "", + "forbidden_ip": "", + "forbidden_port": "", + "protocol_param": "", + "obfs_param": "", + "uuid": "f5c3822f-2eca-38f6-b0d6-78533d15d372", + "protocol": "origin", + "obfs": "plain", + "port": 10373, + "passwd": "2_bBtiUI", + "u": 5311482594, + "id": 2, + "email": "2_2_bBtiUI" + }, + { + "is_multi_user": 0, + "method": "aes-256-gcm", + "d": 11714963720, + "node_speedlimit": 500, + "node_connector": 14, + "disconnect_ip": "", + "forbidden_ip": "127.0.0.0/8,::1/128", + "forbidden_port": "", + "protocol_param": "", + "obfs_param": "", + "uuid": "c9f311cd-0aaa-31ff-a0b7-11463c17e863", + "protocol": "origin", + "obfs": "plain", + "port": 10556, + "passwd": "4_6TUdjP", + "u": 74239142, + "id": 4, + "email": "4_4_6TUdjP" + } + ] + let result = {ret:1, data: userData} + console.info('GET /users/ result:', result) + res.send(result) +}); + + + + +// POST /aliveip 上送用户在线ip +router.post('/aliveip', async function (req, res) { + + console.info('POST /users/aliveip nodeId:', req.query.node_id) + console.info('POST /users/aliveip body:', req.body) + + res.send({ret:1, data:'ok'}) +}) + +// POST /traffic +router.post('/traffic', async function (req, res) { + console.info('POST /users/traffic nodeId:', req.query.node_id) + console.info('POST /users/traffic body:', req.body) + // create user in req.body + res.send({ret:1, data:'ok'}) +}) + + +router.post('/detectlog', async function(req, res, next) { + console.info('POST /users/detectlog nodeId:', req.query.node_id) + console.info('POST /users/detectlog body:', req.body) + res.send({ret:1, data:'ok'}) +}); + +module.exports = router;//暴露模块