mirror of
https://github.com/HackPlan/RootPanel.git
synced 2026-04-01 10:43:02 +08:00
remove not yet refactored plugins temporarily
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
child_process = require 'child_process'
|
||||
|
||||
service = require './service'
|
||||
{requireInService} = require '../../core/middleware'
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
module.exports = exports = express.Router()
|
||||
|
||||
exports.use requireInService 'memcached'
|
||||
|
||||
exports.post '/switch', (req, res) ->
|
||||
unless req.body.enable in [true, false]
|
||||
return res.error 'invalid_enable'
|
||||
|
||||
service.switch req.account, req.body.enable, ->
|
||||
res.json {}
|
||||
@@ -1,12 +0,0 @@
|
||||
action = require './action'
|
||||
service = require './service'
|
||||
|
||||
module.exports =
|
||||
name: 'memcached'
|
||||
type: 'service'
|
||||
|
||||
action: action
|
||||
service: service
|
||||
|
||||
switch: true
|
||||
switch_status: service.switch_status
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "Memcached",
|
||||
"description": "Memcached 提供了基于内存的高速缓存"
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
child_process = require 'child_process'
|
||||
jade = require 'jade'
|
||||
path = require 'path'
|
||||
tmp = require 'tmp'
|
||||
fs = require 'fs'
|
||||
|
||||
plugin = require '../../core/pluggable'
|
||||
monitor = require '../linux/monitor'
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
MEMCACHED_FLAGS = '-d -m 16'
|
||||
|
||||
module.exports =
|
||||
enable: (account, callback) ->
|
||||
callback()
|
||||
|
||||
delete: (account, callback) ->
|
||||
callback()
|
||||
|
||||
switch: (account, is_enable, callback) ->
|
||||
if is_enable
|
||||
app.redis.del 'rp:process_list', =>
|
||||
@switch_status account, (is_act_enable) ->
|
||||
if is_act_enable
|
||||
return callback()
|
||||
|
||||
child_process.exec pluggable.sudoSu(account, "memcached #{MEMCACHED_FLAGS} -s ~/memcached.sock"), (err) ->
|
||||
throw err if err
|
||||
app.redis.del 'rp:process_list', ->
|
||||
callback()
|
||||
else
|
||||
child_process.exec pluggable.sudoSu(account, "pkill -exf -u #{account.username} \"memcached #{MEMCACHED_FLAGS} -s /home/#{account.username}/memcached.sock\""), ->
|
||||
callback()
|
||||
|
||||
switch_status: (account, callback) ->
|
||||
monitor.getProcessList (plist) ->
|
||||
process = _.find plist, (i) ->
|
||||
return i.user == account.username and i.command == "memcached #{MEMCACHED_FLAGS} -s /home/#{account.username}/memcached.sock"
|
||||
|
||||
callback if process then true else false
|
||||
@@ -1,65 +0,0 @@
|
||||
crypto = require 'crypto'
|
||||
|
||||
{requireInService} = require '../../core/middleware'
|
||||
|
||||
mongodb = app.plugins.mongodb
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
module.exports = exports = express.Router()
|
||||
|
||||
exports.use requireInService 'mongodb'
|
||||
|
||||
exports.post '/update_password', (req, res) ->
|
||||
unless req.body.password or /^[A-Za-z0-9\-_]+$/.test req.body.password
|
||||
return res.error 'invalid_password'
|
||||
|
||||
md5 = crypto.createHash 'md5'
|
||||
md5.update "#{req.account.username}:mongo:#{req.body.password}"
|
||||
pwd = md5.digest 'hex'
|
||||
|
||||
mongodb.admin_users.update {user: req.account.username},
|
||||
$set:
|
||||
pwd: pwd
|
||||
, (err, result) ->
|
||||
mongodb.admin.listDatabases (err, result) ->
|
||||
dbs = _.filter result.databases, (i) ->
|
||||
return i.name[..req.account.username.length] == "#{req.account.username}_"
|
||||
|
||||
async.each dbs, (db, callback) ->
|
||||
db_users = app.db.db(db.name).collection 'system.users'
|
||||
db_users.update {user: req.account.username},
|
||||
$set:
|
||||
pwd: pwd
|
||||
, ->
|
||||
callback()
|
||||
, ->
|
||||
res.json {}
|
||||
|
||||
exports.post '/create_database', (req, res) ->
|
||||
unless req.body.name[..req.account.username.length] == "#{req.account.username}_"
|
||||
return res.error 'invalid_name'
|
||||
|
||||
unless /^[A-Za-z0-9_]+$/.test req.body.name
|
||||
return res.error 'invalid_name'
|
||||
|
||||
mongodb.admin_users.findOne
|
||||
user: req.account.username
|
||||
, (err, result) ->
|
||||
db_users = app.db.db(req.body.name).collection 'system.users'
|
||||
db_users.insert
|
||||
user: req.account.username
|
||||
pwd: result.pwd
|
||||
roles: ['readWrite', 'dbAdmin']
|
||||
, (err) ->
|
||||
res.json {}
|
||||
|
||||
exports.post '/delete_database', (req, res) ->
|
||||
unless req.body.name[..req.account.username.length] == "#{req.account.username}_"
|
||||
return res.error 'invalid_name'
|
||||
|
||||
unless /^[A-Za-z0-9_]+$/.test req.body.name
|
||||
return res.error 'invalid_name'
|
||||
|
||||
app.db.db(req.body.name).dropDatabase ->
|
||||
res.json {}
|
||||
@@ -1,15 +0,0 @@
|
||||
app.plugins.mongodb = {}
|
||||
|
||||
action = require './action'
|
||||
service = require './service'
|
||||
|
||||
module.exports =
|
||||
name: 'mongodb'
|
||||
type: 'service'
|
||||
|
||||
action: action
|
||||
service: service
|
||||
|
||||
panel:
|
||||
widget: service.widget
|
||||
script: '/script/panel.js'
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "MongoDB",
|
||||
"description": "MongoDB 是世界上最流行的非关系型数据库之一"
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
jade = require 'jade'
|
||||
path = require 'path'
|
||||
async = require 'async'
|
||||
crypto = require 'crypto'
|
||||
|
||||
config = require '../../config'
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
mongodb = app.plugins.mongodb
|
||||
|
||||
mongodb.admin = app.db.admin()
|
||||
mongodb.admin.authenticate config.mongodb.user, config.mongodb.password, ->
|
||||
mongodb.admin_users = app.db.db('admin').collection 'system.users'
|
||||
|
||||
module.exports =
|
||||
enable: (account, callback) ->
|
||||
md5 = crypto.createHash 'md5'
|
||||
md5.update "#{account.username}:mongo:#{mAccount.randomSalt()}"
|
||||
pwd = md5.digest 'hex'
|
||||
|
||||
mongodb.admin_users.insert
|
||||
user: account.username
|
||||
pwd: pwd
|
||||
roles: []
|
||||
, (err, result) ->
|
||||
callback()
|
||||
|
||||
delete: (account, callback) ->
|
||||
mongodb.admin_users.remove
|
||||
user: account.username
|
||||
, (err) ->
|
||||
mongodb.admin.listDatabases (err, result) ->
|
||||
dbs = _.filter result.databases, (i) ->
|
||||
return i.name[..account.username.length] == "#{account.username}_"
|
||||
|
||||
async.each dbs, (db, callback) ->
|
||||
app.db.db(db.name).dropDatabase ->
|
||||
callback()
|
||||
, ->
|
||||
callback()
|
||||
|
||||
widget: (account, callback) ->
|
||||
mongodb.admin.listDatabases (err, result) ->
|
||||
dbs = _.filter result.databases, (i) ->
|
||||
return i.name[..account.username.length] == "#{account.username}_"
|
||||
|
||||
jade.renderFile path.join(__dirname, 'view/widget.jade'),
|
||||
account: account
|
||||
dbs: dbs
|
||||
, (err, html) ->
|
||||
callback html
|
||||
|
||||
storage: (account, callback) ->
|
||||
mongodb.admin.listDatabases (err, result) ->
|
||||
dbs = _.filter result.databases, (i) ->
|
||||
return i.name[..account.username.length] == "#{account.username}_"
|
||||
|
||||
callback null, _.reduce dbs, (memo, db) ->
|
||||
return memo + db.sizeOnDisk / 1024 / 1024
|
||||
, 0
|
||||
@@ -1,34 +0,0 @@
|
||||
$ ->
|
||||
$('#widget-mongodb button.create-database').click ->
|
||||
$.post '/plugin/mongodb/create_database', JSON.stringify
|
||||
name: $(@).parents('.input-group').find('input').val()
|
||||
.fail (jqXHR) ->
|
||||
if jqXHR.responseJSON?.error
|
||||
alert jqXHR.responseJSON.error
|
||||
else
|
||||
alert jqXHR.statusText
|
||||
.success ->
|
||||
location.reload()
|
||||
|
||||
$('#widget-mongodb button.delete-database').click ->
|
||||
if window.confirm 'Are you sure?'
|
||||
$.post '/plugin/mongodb/delete_database', JSON.stringify
|
||||
name: $(@).parents('tr').data 'name'
|
||||
.fail (jqXHR) ->
|
||||
if jqXHR.responseJSON?.error
|
||||
alert jqXHR.responseJSON.error
|
||||
else
|
||||
alert jqXHR.statusText
|
||||
.success ->
|
||||
location.reload()
|
||||
|
||||
$('#widget-mongodb button.update-password').click ->
|
||||
$.post '/plugin/mongodb/update_password', JSON.stringify
|
||||
password: $(@).parents('.input-group').find('input').val()
|
||||
.fail (jqXHR) ->
|
||||
if jqXHR.responseJSON?.error
|
||||
alert jqXHR.responseJSON.error
|
||||
else
|
||||
alert jqXHR.statusText
|
||||
.success ->
|
||||
location.reload()
|
||||
@@ -1,34 +0,0 @@
|
||||
header MongoDB
|
||||
.col-md-6
|
||||
.panel.panel-success
|
||||
.panel-heading
|
||||
h3.panel-title 新建数据库
|
||||
.panel-body
|
||||
.input-group
|
||||
input.form-control(value='#{account.username}_')
|
||||
span.input-group-btn
|
||||
button.create-database.btn.btn-default(type='button') 提交
|
||||
.panel.panel-warning
|
||||
.panel-heading
|
||||
h3.panel-title 设置 MongoDB 密码
|
||||
.panel-body
|
||||
.input-group
|
||||
input.form-control(type='password')
|
||||
span.input-group-btn
|
||||
button.update-password.btn.btn-default(type='button') 提交
|
||||
|
||||
.col-md-6
|
||||
table(style= 'table-layout: fixed;').table.table-hover
|
||||
thead
|
||||
tr
|
||||
td(style= 'width: 200px;') 数据库
|
||||
td 磁盘占用
|
||||
td
|
||||
tbody
|
||||
for db in dbs
|
||||
tr(data-name= db.name)
|
||||
td(style= 'white-space: nowrap; overflow: hidden;', title= db.name)= db.name
|
||||
td #{(db.sizeOnDisk / 1024 / 1024).toFixed(1)}M
|
||||
td
|
||||
button.delete-database.btn.btn-danger.btn-xs
|
||||
span.glyphicon.glyphicon-remove-sign
|
||||
@@ -1,19 +0,0 @@
|
||||
mysql = require 'mysql'
|
||||
|
||||
plugin = require '../../core/pluggable'
|
||||
{requireInService} = require '../../core/middleware'
|
||||
|
||||
connection = mysql.createConnection config.plugins.mysql.connection
|
||||
connection.connect()
|
||||
|
||||
module.exports = exports = express.Router()
|
||||
|
||||
exports.use requireInService 'mysql'
|
||||
|
||||
exports.post '/update_password', (req, res) ->
|
||||
unless req.body.password or /^[A-Za-z0-9\-_]+$/.test req.body.password
|
||||
return res.error 'invalid_password'
|
||||
|
||||
connection.query "SET PASSWORD FOR '#{req.account.username}'@'localhost' = PASSWORD('#{req.body.password}');", (err, rows, fields) ->
|
||||
throw err if err
|
||||
res.json {}
|
||||
@@ -1,13 +0,0 @@
|
||||
action = require './action'
|
||||
service = require './service'
|
||||
|
||||
module.exports =
|
||||
name: 'mysql'
|
||||
type: 'service'
|
||||
|
||||
action: action
|
||||
service: service
|
||||
|
||||
panel:
|
||||
widget: service.widget
|
||||
script: '/script/panel.js'
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "MySQL",
|
||||
"description": "MySQL 是世界上最流行的关系型数据库之一"
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
jade = require 'jade'
|
||||
path = require 'path'
|
||||
mysql = require 'mysql'
|
||||
async = require 'async'
|
||||
|
||||
config = require '../../config'
|
||||
plugin = require '../../core/pluggable'
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
connection = mysql.createConnection config.plugins.mysql.connection
|
||||
connection.connect()
|
||||
|
||||
module.exports =
|
||||
enable: (account, callback) ->
|
||||
connection.query "CREATE USER '#{account.username}'@'localhost' IDENTIFIED BY '#{mAccount.randomSalt()}';", (err, rows) ->
|
||||
throw err if err
|
||||
|
||||
connection.query "GRANT ALL PRIVILEGES ON `#{account.username}\\_%%` . * TO '#{account.username}'@'localhost';", (err, rows) ->
|
||||
throw err if err
|
||||
callback()
|
||||
|
||||
delete: (account, callback) ->
|
||||
connection.query "DROP USER '#{account.username}'@'localhost';", (err, rows) ->
|
||||
throw err if err
|
||||
|
||||
connection.query "SHOW DATABASES LIKE '#{account.username}_%';", (err, rows) ->
|
||||
throw err if err
|
||||
|
||||
databases_to_delete = _.filter _.pluck(rows, "Database (#{account.username}_%)"), (item) ->
|
||||
if item[..account.username.length] == "#{account.username}_"
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
||||
async.each databases_to_delete, (name, callback) ->
|
||||
connection.query "DROP DATABASE `#{name}`;", (err, rows) ->
|
||||
throw err if err
|
||||
callback()
|
||||
, ->
|
||||
callback()
|
||||
|
||||
widget: (account, callback) ->
|
||||
connection.query "SELECT `table_schema` 'name', sum(`data_length` + `index_length`) / 1024 / 1024 'size', sum(`data_free`) / 1024 / 1024 'free' FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` LIKE '#{account.username}_%' GROUP BY table_schema;", (err, rows) ->
|
||||
jade.renderFile path.join(__dirname, 'view/widget.jade'),
|
||||
dbs: rows
|
||||
, (err, html) ->
|
||||
callback html
|
||||
|
||||
storage: (account, callback) ->
|
||||
connection.query "SELECT `table_schema` 'name', sum(`data_length` + `index_length`) / 1024 / 1024 'size', sum(`data_free`) / 1024 / 1024 'free' FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` LIKE '#{account.username}_%' GROUP BY table_schema;", (err, rows) ->
|
||||
callback null, _.reduce rows, (memo, db) ->
|
||||
return memo + db.size
|
||||
, 0
|
||||
@@ -1,11 +0,0 @@
|
||||
$ ->
|
||||
$('#widget-mysql .update-password button').click ->
|
||||
$.post '/plugin/mysql/update_password/', JSON.stringify
|
||||
password: $('#widget-mysql .update-password input').val()
|
||||
.fail (jqXHR) ->
|
||||
if jqXHR.responseJSON?.error
|
||||
alert jqXHR.responseJSON.error
|
||||
else
|
||||
alert jqXHR.statusText
|
||||
.success ->
|
||||
location.reload()
|
||||
@@ -1,23 +0,0 @@
|
||||
header MySQL
|
||||
.col-md-6
|
||||
.panel.panel-warning
|
||||
.panel-heading
|
||||
h3.panel-title 设置 MySQL 密码
|
||||
.panel-body
|
||||
.input-group.update-password
|
||||
input.form-control(type='password')
|
||||
span.input-group-btn
|
||||
button.btn.btn-default(type='button') 提交
|
||||
.col-md-6
|
||||
table(style= 'table-layout: fixed;').table.table-hover
|
||||
thead
|
||||
tr
|
||||
td(style= 'width: 200px;') 数据库
|
||||
td 体积
|
||||
td 磁盘占用
|
||||
tbody
|
||||
for db in dbs
|
||||
tr
|
||||
td(style= 'white-space: nowrap; overflow: hidden;', title= db.name)= db.name
|
||||
td #{db.size.toFixed(1)}M
|
||||
td #{(db.size + db.free).toFixed(1)}M
|
||||
@@ -1,100 +0,0 @@
|
||||
child_process = require 'child_process'
|
||||
|
||||
service = require './service'
|
||||
configure = require './configure'
|
||||
|
||||
{requireInService, getParam} = require '../../core/middleware'
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
module.exports = exports = express.Router()
|
||||
|
||||
exports.use requireInService 'nginx'
|
||||
|
||||
sample =
|
||||
_id: '53c96734c2dad7d6208a0fbe'
|
||||
is_enable: true
|
||||
listen: 80
|
||||
server_name: ['domain1', 'domain2']
|
||||
auto_index: false
|
||||
index: ['index.html', 'index.html']
|
||||
root: '/home/user/web'
|
||||
location:
|
||||
'/':
|
||||
try_files: ['$uri', '$uri/', '/index.php?$args']
|
||||
|
||||
'~ \\.php$':
|
||||
fastcgi_pass: 'unix:///home/user/phpfpm.sock'
|
||||
fastcgi_index: ['index.php']
|
||||
include: 'fastcgi_params'
|
||||
|
||||
exports.all '/site_config', getParam, (req, res) ->
|
||||
site = _.find req.account.attribute.plugin.nginx.sites, (i) ->
|
||||
return i._id.toString() == req.body.id
|
||||
|
||||
site.id = site._id
|
||||
delete site._id
|
||||
|
||||
res.json site
|
||||
|
||||
exports.post '/update_site', (req, res) ->
|
||||
unless req.body.action in ['create', 'update', 'delete']
|
||||
return res.error 'invalid_action'
|
||||
|
||||
checkSite = (callback) ->
|
||||
if req.body.action == 'create'
|
||||
callback null
|
||||
else
|
||||
mAccount.findOne
|
||||
'attribute.plugin.nginx.sites._id': new ObjectID req.body.id
|
||||
, (err, account) ->
|
||||
if account?._id.toString() == req.account._id.toString()
|
||||
callback null
|
||||
else
|
||||
callback true
|
||||
|
||||
checkSiteConfig = (callback) ->
|
||||
unless req.body.action == 'delete'
|
||||
if req.body.type == 'json'
|
||||
configure.assert req.account, req.body.config, req.body.id, (err) ->
|
||||
callback err
|
||||
else
|
||||
callback 'invalid_type'
|
||||
else
|
||||
callback null
|
||||
|
||||
checkSite (err) ->
|
||||
if err
|
||||
return res.error 'forbidden'
|
||||
|
||||
checkSiteConfig (err) ->
|
||||
if err
|
||||
return res.error err
|
||||
|
||||
removeSite = (callback) ->
|
||||
mAccount.update _id: req.account._id,
|
||||
$pull:
|
||||
'attribute.plugin.nginx.sites':
|
||||
'_id': new ObjectID req.body.id
|
||||
, callback
|
||||
|
||||
addSite = (callback) ->
|
||||
req.body.config._id = new ObjectID()
|
||||
req.body.config = _.pick req.body.config, _.keys(sample)
|
||||
mAccount.update _id: req.account._id,
|
||||
$push:
|
||||
'attribute.plugin.nginx.sites': req.body.config
|
||||
, callback
|
||||
|
||||
execModification = (callback) ->
|
||||
if req.body.action == 'create'
|
||||
addSite callback
|
||||
else if req.body.action == 'update'
|
||||
removeSite ->
|
||||
addSite callback
|
||||
else if req.body.action == 'delete'
|
||||
removeSite callback
|
||||
|
||||
execModification ->
|
||||
service.writeConfig req.account, ->
|
||||
res.json {}
|
||||
@@ -1,129 +0,0 @@
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
exports.checkHomeFilePath = (account, path) ->
|
||||
home_dir = "/home/#{account.username}/"
|
||||
|
||||
unless /^[/A-Za-z0-9_\-\.]+\/?$/.test path
|
||||
return false
|
||||
|
||||
unless path.slice(0, home_dir.length) == home_dir
|
||||
return false
|
||||
|
||||
unless path.length < 512
|
||||
return false
|
||||
|
||||
unless path.slice(-3) != '/..'
|
||||
return false
|
||||
|
||||
unless path.indexOf('/../') == -1
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
exports.checkHomeUnixSocket = (account, path) ->
|
||||
fastcgi_prefix = 'unix://'
|
||||
|
||||
unless path.slice(0, fastcgi_prefix.length) == fastcgi_prefix
|
||||
return false
|
||||
|
||||
unless exports.checkHomeFilePath account, path.slice fastcgi_prefix.length
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
exports.assert = (account, config, site_id, callback) ->
|
||||
config.index ?= ['index.html']
|
||||
config.location ?= {}
|
||||
|
||||
unless config.is_enable == false
|
||||
config.is_enable = true
|
||||
|
||||
unless config.listen in [80]
|
||||
return callback 'invalid_listen'
|
||||
|
||||
async.each config.server_name, (domain, callback) ->
|
||||
unless utils.rx.domain.test domain
|
||||
return callback 'invalid_server_name'
|
||||
|
||||
mAccount.findOne
|
||||
'attribute.plugin.nginx.sites.server_name': domain
|
||||
, (err, result) ->
|
||||
unless result
|
||||
return callback null
|
||||
|
||||
site = _.find result.attribute.plugin.nginx.sites, (i) ->
|
||||
return domain in i.server_name
|
||||
|
||||
if site._id.toString() == site_id?.toString()
|
||||
callback null
|
||||
else
|
||||
callback 'unavailable_server_name'
|
||||
|
||||
, (err) ->
|
||||
if err
|
||||
return callback err
|
||||
|
||||
if config.auto_index
|
||||
config.auto_index = if config.auto_index then true else false
|
||||
|
||||
unless _.isArray config.index
|
||||
return callback 'invalid_index'
|
||||
|
||||
for file in config.index
|
||||
unless utils.rx.filename.test file
|
||||
return callback 'invalid_index'
|
||||
|
||||
if config.root
|
||||
unless utils.checkHomeFilePath account, config.root
|
||||
return callback 'invalid_root'
|
||||
|
||||
for path, rules of config.location
|
||||
unless path in ['/', '~ \\.php$']
|
||||
return callback 'invalid_location'
|
||||
|
||||
for name, value of rules
|
||||
switch name
|
||||
when 'fastcgi_pass'
|
||||
rules['fastcgi_index'] ?= ['index.php']
|
||||
unless utils.checkHomeUnixSocket account, value
|
||||
return callback 'invalid_fastcgi_pass'
|
||||
|
||||
when 'uwsgi_pass'
|
||||
unless utils.checkHomeUnixSocket account, value
|
||||
return callback 'invalid_fastcgi_pass'
|
||||
|
||||
when 'proxy_pass'
|
||||
rules['proxy_redirect'] ?= false
|
||||
unless utils.checkHomeUnixSocket(account, value) or utils.rx.url.test value
|
||||
return callback 'invalid_proxy_pass'
|
||||
|
||||
when 'proxy_set_header'
|
||||
for header_name, header_value of value
|
||||
switch header_name
|
||||
when 'Host'
|
||||
unless header_value == '$host' or utils.rx.domain.test header_value
|
||||
return callback 'invalid_proxy_set_header'
|
||||
else
|
||||
return callback 'invalid_proxy_set_header'
|
||||
|
||||
when 'proxy_redirect'
|
||||
rules['proxy_redirect'] = if value then true else false
|
||||
|
||||
when 'fastcgi_index'
|
||||
for file in value
|
||||
unless utils.rx.filename.test file
|
||||
return callback 'invalid_fastcgi_index'
|
||||
|
||||
when 'include'
|
||||
unless value in ['fastcgi_params', 'uwsgi_params']
|
||||
return callback 'invalid_include'
|
||||
|
||||
when 'try_files'
|
||||
for item in value
|
||||
unless item in ['$uri', '$uri/', '/index.php?$args']
|
||||
return callback 'invalid_try_files'
|
||||
|
||||
else
|
||||
return callback 'unknown_command'
|
||||
|
||||
callback null
|
||||
@@ -1,14 +0,0 @@
|
||||
action = require './action'
|
||||
service = require './service'
|
||||
|
||||
module.exports =
|
||||
name: 'nginx'
|
||||
type: 'service'
|
||||
|
||||
action: action
|
||||
service: service
|
||||
|
||||
panel:
|
||||
widget: service.widget
|
||||
script: '/script/panel.js'
|
||||
style:'/style/panel.css'
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "Nginx",
|
||||
"description": "Nginx 提供了自定义系统 80 端口上的 Nginx 的配置的功能"
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
child_process = require 'child_process'
|
||||
jade = require 'jade'
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
|
||||
plugin = require '../../core/pluggable'
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
template =
|
||||
site_configure: fs.readFileSync("#{__dirname}/template/site_configure.conf").toString()
|
||||
user_configure: fs.readFileSync("#{__dirname}/template/user_configure.conf").toString()
|
||||
|
||||
siteSummary = (site) ->
|
||||
type = do ->
|
||||
unless site['location']['/']
|
||||
return 'static'
|
||||
|
||||
if site['location']['/']['proxy_pass']
|
||||
return 'proxy'
|
||||
|
||||
if site['location']['/']['uwsgi_pass']
|
||||
return 'uwsgi'
|
||||
|
||||
if site['location']['/']?['try_files']
|
||||
for item in site['location']['/']['try_files']
|
||||
if item.match(/\.php/)
|
||||
return 'factcgi'
|
||||
|
||||
return 'static'
|
||||
|
||||
prefix = "(#{if site.is_enable then '√' else 'x'}) #{type};"
|
||||
|
||||
switch type
|
||||
when 'static', 'factcgi'
|
||||
return "#{prefix} root: #{site['root']}"
|
||||
when 'proxy'
|
||||
return "#{prefix} url: " + site['location']['/']['proxy_pass']
|
||||
when 'uwsgi'
|
||||
return "#{prefix} socket: " + site['location']['/']['uwsgi_pass']
|
||||
|
||||
module.exports =
|
||||
enable: (account, callback) ->
|
||||
mAccount.update {_id: account._id},
|
||||
$set:
|
||||
'attribute.plugin.nginx.sites': []
|
||||
, ->
|
||||
callback()
|
||||
|
||||
delete: (account, callback) ->
|
||||
child_process.exec "sudo rm /etc/nginx/sites-enabled/#{account.username}.conf", ->
|
||||
callback()
|
||||
|
||||
writeConfig: (account, callback) ->
|
||||
mAccount.findId account._id, (err, account) ->
|
||||
unless account.attribute.plugin.nginx.sites
|
||||
return callback()
|
||||
|
||||
sites_configure = []
|
||||
|
||||
for site in account.attribute.plugin.nginx.sites
|
||||
if site.is_enable
|
||||
sites_configure.push _.template template.site_configure,
|
||||
site: site
|
||||
|
||||
user_configure = _.template template.user_configure,
|
||||
sites: sites_configure
|
||||
|
||||
pluggable.writeConfig "/etc/nginx/sites-enabled/#{account.username}.conf", user_configure, ->
|
||||
child_process.exec 'sudo service nginx reload', (err) ->
|
||||
throw err if err
|
||||
callback()
|
||||
|
||||
siteSummary: siteSummary
|
||||
|
||||
widget: (account, callback) ->
|
||||
jade.renderFile path.join(__dirname, 'view/widget.jade'),
|
||||
account: account
|
||||
siteSummary: siteSummary
|
||||
, (err, html) ->
|
||||
throw err if err
|
||||
callback html
|
||||
@@ -1,175 +0,0 @@
|
||||
$ ->
|
||||
syncToJSON = ->
|
||||
username = $('.nav.navbar-nav.navbar-right li:first a').text()
|
||||
|
||||
try
|
||||
config = JSON.parse($('#nginx-type-json textarea').val())
|
||||
catch e
|
||||
config = {}
|
||||
|
||||
config['listen'] ?= 80
|
||||
|
||||
config['is_enable'] = $('.option-is-enable input').prop('checked')
|
||||
config['server_name'] = $('.option-server-name input').val().split ' '
|
||||
|
||||
switch $('.option-type :radio:checked').val()
|
||||
when 'fastcgi'
|
||||
config['root'] = $('.option-root input').val() or $('.option-root input').prop('placeholder')
|
||||
config['index'] ?= ['index.php', 'index.html']
|
||||
config['location'] ?= {}
|
||||
config['location']['/'] =
|
||||
try_files: ['$uri', '$uri/', '/index.php?$args']
|
||||
config['location']['~ \\.php$'] =
|
||||
fastcgi_pass: "unix:///home/#{username}/phpfpm.sock"
|
||||
include: 'fastcgi_params'
|
||||
|
||||
when 'proxy'
|
||||
config['location'] ?= {}
|
||||
config['location']['/'] =
|
||||
proxy_pass: $('.option-proxy input').val() or $('.option-proxy input').prop('placeholder')
|
||||
proxy_set_header:
|
||||
Host: '$host'
|
||||
|
||||
when 'uwsgi'
|
||||
config['location'] ?= {}
|
||||
config['location']['/'] =
|
||||
uwsgi_pass: $('.option-uwsgi input').val() or $('.option-uwsgi input').prop('placeholder')
|
||||
include: 'uwsgi_params'
|
||||
|
||||
when 'static'
|
||||
config['index'] ?= ['index.html']
|
||||
config['root'] = $('.option-root input').val() or $('.option-root input').prop('placeholder')
|
||||
|
||||
$('#nginx-type-json textarea').val JSON.stringify(config, null, ' ')
|
||||
return config
|
||||
|
||||
syncToGuide = ->
|
||||
$('.json-error').parent().addClass 'hide'
|
||||
|
||||
try
|
||||
config = JSON.parse($('#nginx-type-json textarea').val())
|
||||
catch e
|
||||
return
|
||||
|
||||
$('.option-is-enable input').prop 'checked', config['is_enable']
|
||||
$('.option-server-name input').val config['server_name']?.join ' '
|
||||
$('.option-root input').val config['root']
|
||||
|
||||
type = do ->
|
||||
unless config['location']['/']
|
||||
return 'static'
|
||||
|
||||
if config['location']['/']['proxy_pass']
|
||||
return 'proxy'
|
||||
|
||||
if config['location']['/']['uwsgi_pass']
|
||||
return 'uwsgi'
|
||||
|
||||
if config['location']['/']?['try_files']
|
||||
for item in config['location']['/']['try_files']
|
||||
if item.match(/\.php/)
|
||||
return 'factcgi'
|
||||
|
||||
return 'static'
|
||||
|
||||
$("#nginx-modal :radio[value=#{type}]").click()
|
||||
|
||||
switch type
|
||||
when 'proxy'
|
||||
$('.option-proxy input').val config['location']['/']['proxy_pass']
|
||||
when 'uwsgi'
|
||||
$('.option-uwsgi input').val config['location']['/']['uwsgi_pass']
|
||||
when 'static', 'fastcgi'
|
||||
$('.option-root input').val config['root']
|
||||
|
||||
$('#nginx-type-json textarea').on 'change keyup paste', ->
|
||||
try
|
||||
JSON.parse($('#nginx-type-json textarea').val())
|
||||
$('.json-error').parent().addClass 'hide'
|
||||
catch err
|
||||
console.log err
|
||||
$('.json-error').text err.toString()
|
||||
$('.json-error').parent().removeClass 'hide'
|
||||
|
||||
$('#nginx-modal ul li a').click ->
|
||||
switch $(@).prop('href').match(/.*#nginx-type-(.*)/)[1]
|
||||
when 'json'
|
||||
syncToJSON()
|
||||
when 'guide'
|
||||
syncToGuide()
|
||||
|
||||
$('#nginx-modal .radio input').click ->
|
||||
options = ['root', 'proxy', 'uwsgi']
|
||||
|
||||
mapping_table =
|
||||
fastcgi: ['root']
|
||||
proxy: ['proxy']
|
||||
uwsgi: ['uwsgi']
|
||||
static: ['root']
|
||||
|
||||
options_to_show = mapping_table[$(@).val()]
|
||||
|
||||
for item in options
|
||||
if item in options_to_show
|
||||
$("#nginx-modal .option-#{item}").removeClass 'hide'
|
||||
else
|
||||
$("#nginx-modal .option-#{item}").addClass 'hide'
|
||||
|
||||
$('#nginx-modal .modal-footer button.btn-success').click ->
|
||||
type = $('#nginx-modal ul.config-type').find('.active a').prop('href').match(/.*#nginx-type-(.*)/)[1]
|
||||
|
||||
if type == 'guide'
|
||||
config = syncToJSON()
|
||||
|
||||
else if type == 'json'
|
||||
try
|
||||
config = JSON.parse($('#nginx-type-json textarea').val())
|
||||
catch e
|
||||
return alert 'Invalid JSON'
|
||||
|
||||
else
|
||||
return alert 'Coming Soon'
|
||||
|
||||
$.post '/plugin/nginx/update_site/', JSON.stringify
|
||||
action: if config.id then 'update' else 'create'
|
||||
id: config.id
|
||||
type: 'json'
|
||||
config: config
|
||||
.fail (jqXHR) ->
|
||||
if jqXHR.responseJSON?.error
|
||||
alert jqXHR.responseJSON.error
|
||||
else
|
||||
alert jqXHR.statusText
|
||||
|
||||
.done ->
|
||||
location.reload()
|
||||
|
||||
$('#widget-nginx table .btn-danger').click ->
|
||||
if window.confirm 'Are you sure?'
|
||||
$.post '/plugin/nginx/update_site', JSON.stringify
|
||||
action: 'delete'
|
||||
id: $(@).parents('tr').data 'id'
|
||||
.fail (jqXHR) ->
|
||||
if jqXHR.responseJSON?.error
|
||||
alert jqXHR.responseJSON.error
|
||||
else
|
||||
alert jqXHR.statusText
|
||||
.success ->
|
||||
location.reload()
|
||||
|
||||
$('#widget-nginx table .btn-success').click ->
|
||||
$('#nginx-modal .site-id').text ''
|
||||
|
||||
$('#widget-nginx table button.btn-info').click ->
|
||||
$.post '/plugin/nginx/site_config', JSON.stringify
|
||||
id: $(@).parents('tr').data 'id'
|
||||
.fail (jqXHR) ->
|
||||
if jqXHR.responseJSON?.error
|
||||
alert jqXHR.responseJSON.error
|
||||
else
|
||||
alert jqXHR.statusText
|
||||
.success (data) ->
|
||||
$('#nginx-type-json textarea').val JSON.stringify(data, null, ' ')
|
||||
syncToGuide()
|
||||
$('#nginx-modal .site-id').text data.id
|
||||
$('#nginx-modal').modal 'show'
|
||||
@@ -1,21 +0,0 @@
|
||||
#nginx-type-json {
|
||||
textarea {
|
||||
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-pane p {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.tab-pane {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.modal-dialog {
|
||||
width: 800px;
|
||||
margin: 80px auto;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
server {
|
||||
listen <%= site.listen %>;
|
||||
server_name <%= site.server_name.join(' ') %>;
|
||||
|
||||
index <%= site.index.join(' ') %>;
|
||||
autoindex <%= site.auto_index ? 'on' : 'off' %>;
|
||||
|
||||
<% if(site.root) { %>
|
||||
root <%= site.root %>;
|
||||
<% } %>
|
||||
|
||||
<% _.each(site.location, function(rules, path) { %>
|
||||
location <%= path %> {
|
||||
<% _.each(rules, function(param, command) { %>
|
||||
<% if(_.isArray(param)) { %>
|
||||
<%= command %> <%= param.join(' ') %>;
|
||||
<% } else if(_.isBoolean(param)) { %>
|
||||
<%= command %> <%= param ? 'on' : 'off' %>;
|
||||
<% } else if(_.isObject(param)) { %>
|
||||
<% _.each(param, function(param2, param1) { %>
|
||||
<%= command %> <%= param1 %> <%= param2 %>;
|
||||
<% }); %>
|
||||
<% } else { %>
|
||||
<%= command %> <%= param %>;
|
||||
<% } %>
|
||||
<% }); %>
|
||||
}
|
||||
<% }); %>
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
<% _.each(sites, function(site) { %>
|
||||
<%= site %>
|
||||
<% }) %>
|
||||
@@ -1,97 +0,0 @@
|
||||
header Nginx
|
||||
table.table.table-hover
|
||||
thead
|
||||
tr
|
||||
th 域名
|
||||
th 摘要
|
||||
th
|
||||
button.btn.btn-success.btn-xs(data-toggle='modal', data-target='#nginx-modal')
|
||||
span.glyphicon.glyphicon-plus-sign
|
||||
tbody
|
||||
for site in account.attribute.plugin.nginx.sites
|
||||
tr(data-id= '#{site._id}')
|
||||
td= site.server_name.join(', ')
|
||||
td= siteSummary(site)
|
||||
td(style= 'width: 150px;')
|
||||
button.btn.btn-info.btn-xs
|
||||
span.glyphicon.glyphicon-edit
|
||||
button.btn.btn-danger.btn-xs
|
||||
span.glyphicon.glyphicon-trash
|
||||
|
||||
.modal.fade#nginx-modal(tabindex='-1', role='dialog', aria-hidden='true')
|
||||
.modal-dialog
|
||||
.modal-content
|
||||
.modal-header
|
||||
button.close(type='button', data-dismiss='modal', aria-hidden='true') ×
|
||||
h3.modal-title
|
||||
| Nginx
|
||||
span.small.site-id
|
||||
.modal-body
|
||||
ul.nav.nav-tabs.config-type
|
||||
li.active
|
||||
a(href='#nginx-type-guide', data-toggle='tab') 向导
|
||||
li
|
||||
a(href='#nginx-type-json', data-toggle='tab') JSON
|
||||
li
|
||||
a(href='#nginx-type-original', data-toggle='tab') 原生
|
||||
.tab-content
|
||||
.tab-pane.active#nginx-type-guide
|
||||
form.form-horizontal(role='form')
|
||||
h3 常规
|
||||
.form-group.option-is-enable
|
||||
label.col-sm-2.control-label »
|
||||
.checkbox.col-sm-10
|
||||
label
|
||||
input(type='checkbox', checked)
|
||||
| 启用站点
|
||||
.form-group.option-server-name
|
||||
label.col-sm-2.control-label 域名
|
||||
.col-sm-10
|
||||
input.form-control(type='text', required, placeholder='example.com example.net')
|
||||
|
||||
h3 类型
|
||||
.form-group.option-type
|
||||
label.col-sm-2.control-label »
|
||||
.controls.col-sm-10
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='site-type', value='fastcgi', checked)
|
||||
| fastcgi (PHP)
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='site-type', value='proxy')
|
||||
| proxy (反向代理)
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='site-type', value='uwsgi')
|
||||
| uwsgi (Python)
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='site-type', value='static')
|
||||
| static (静态文件)
|
||||
|
||||
h3 选项
|
||||
.form-group.option-root
|
||||
label.col-sm-2.control-label 根目录
|
||||
.col-sm-10
|
||||
input.form-control(type='text', placeholder='/home/#{account.username}/web')
|
||||
.form-group.option-proxy.hide
|
||||
label.col-sm-2.control-label 源地址
|
||||
.col-sm-10
|
||||
input.form-control(type='text', placeholder='http://127.0.0.1')
|
||||
.form-group.option-uwsgi.hide
|
||||
label.col-sm-2.control-label 源地址
|
||||
.col-sm-10
|
||||
input.form-control(type='text', placeholder='/home/#{account.username}/uwsgi.sock')
|
||||
|
||||
.tab-pane#nginx-type-json
|
||||
form(role='form')
|
||||
textarea.form-control(rows='18')
|
||||
.tab-pane#nginx-type-original
|
||||
p 即将支持
|
||||
.modal-footer
|
||||
p.pull-left.hide
|
||||
span.glyphicon.glyphicon-warning-sign
|
||||
|
|
||||
span.json-error.text-danger 错误信息
|
||||
button.btn.btn-success(type='button') 保存
|
||||
@@ -1,21 +0,0 @@
|
||||
child_process = require 'child_process'
|
||||
|
||||
service = require './service'
|
||||
{requireInService} = require '../../core/middleware'
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
module.exports = exports = express.Router()
|
||||
|
||||
exports.use requireInService 'phpfpm'
|
||||
|
||||
exports.post '/switch', (req, res) ->
|
||||
unless req.body.enable in [true, false]
|
||||
return res.error 'invalid_enable'
|
||||
|
||||
mAccount.update _id: req.account._id,
|
||||
$set:
|
||||
'attribute.plugin.phpfpm.is_enable': req.body.enable
|
||||
, ->
|
||||
service.switch req.account, req.body.enable, ->
|
||||
res.json {}
|
||||
@@ -1,11 +0,0 @@
|
||||
action = require './action'
|
||||
service = require './service'
|
||||
|
||||
module.exports =
|
||||
name: 'phpfpm'
|
||||
type: 'service'
|
||||
|
||||
action: action
|
||||
service: service
|
||||
|
||||
switch: true
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "PHP-FPM",
|
||||
"description": "PHP-FPM 提供了运行 PHP 程序的能力"
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
child_process = require 'child_process'
|
||||
jade = require 'jade'
|
||||
path = require 'path'
|
||||
tmp = require 'tmp'
|
||||
fs = require 'fs'
|
||||
|
||||
plugin = require '../../core/pluggable'
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
module.exports =
|
||||
enable: (account, callback) ->
|
||||
mAccount.update {_id: account._id},
|
||||
$set:
|
||||
'attribute.plugin.phpfpm.is_enable': false
|
||||
, ->
|
||||
callback()
|
||||
|
||||
delete: (account, callback) ->
|
||||
if account.attribute.plugin.phpfpm.is_enable
|
||||
this.switch account, false, callback
|
||||
else
|
||||
callback()
|
||||
|
||||
switch: (account, is_enable, callback) ->
|
||||
restartPhpfpm = ->
|
||||
child_process.exec 'sudo service php5-fpm restart', (err) ->
|
||||
throw err if err
|
||||
callback()
|
||||
|
||||
if is_enable
|
||||
config_content = _.template (fs.readFileSync path.join(__dirname, 'template/fpm-pool.conf')).toString(),
|
||||
account: account
|
||||
|
||||
pluggable.writeConfig "/etc/php5/fpm/pool.d/#{account.username}.conf", config_content, ->
|
||||
restartPhpfpm()
|
||||
else
|
||||
child_process.exec "sudo rm /etc/php5/fpm/pool.d/#{account.username}.conf", ->
|
||||
restartPhpfpm()
|
||||
@@ -1,23 +0,0 @@
|
||||
[<%= account.username %>]
|
||||
|
||||
user = <%= account.username %>
|
||||
group = <%= account.username %>
|
||||
|
||||
listen = /home/<%= account.username %>/phpfpm.sock
|
||||
|
||||
listen.owner = <%= account.username %>
|
||||
listen.group = <%= account.username %>
|
||||
listen.mode = 0660
|
||||
|
||||
pm = ondemand
|
||||
pm.max_children = 3
|
||||
pm.process_idle_timeout = 10s
|
||||
pm.max_requests = 500
|
||||
|
||||
slowlog = /home/<%= account.username %>/phpfpm.slowlog
|
||||
request_slowlog_timeout = 5s
|
||||
request_terminate_timeout = 15s
|
||||
|
||||
php_admin_value[memory_limit] = 128M
|
||||
php_admin_value[error_log] = /home/<%= account.username %>/phpfpm_error.log
|
||||
php_admin_flag[log_errors] = On
|
||||
@@ -1,17 +0,0 @@
|
||||
child_process = require 'child_process'
|
||||
|
||||
service = require './service'
|
||||
{requireInService} = require '../../core/middleware'
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
module.exports = exports = express.Router()
|
||||
|
||||
exports.use requireInService 'redis'
|
||||
|
||||
exports.post '/switch', (req, res) ->
|
||||
unless req.body.enable in [true, false]
|
||||
return res.error 'invalid_enable'
|
||||
|
||||
service.switch req.account, req.body.enable, ->
|
||||
res.json {}
|
||||
@@ -1,12 +0,0 @@
|
||||
action = require './action'
|
||||
service = require './service'
|
||||
|
||||
module.exports =
|
||||
name: 'redis'
|
||||
type: 'service'
|
||||
|
||||
action: action
|
||||
service: service
|
||||
|
||||
switch: true
|
||||
switch_status: service.switch_status
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "Redis",
|
||||
"description": "Redis 提供了更灵活的缓存方案"
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
child_process = require 'child_process'
|
||||
jade = require 'jade'
|
||||
path = require 'path'
|
||||
tmp = require 'tmp'
|
||||
fs = require 'fs'
|
||||
|
||||
plugin = require '../../core/pluggable'
|
||||
monitor = require '../linux/monitor'
|
||||
|
||||
mAccount = require '../../core/model/account'
|
||||
|
||||
module.exports =
|
||||
enable: (account, callback) ->
|
||||
callback()
|
||||
|
||||
delete: (account, callback) ->
|
||||
callback()
|
||||
|
||||
switch: (account, is_enable, callback) ->
|
||||
if is_enable
|
||||
app.redis.del 'rp:process_list', =>
|
||||
@switch_status account, (is_act_enable) ->
|
||||
if is_act_enable
|
||||
return callback()
|
||||
|
||||
child_process.exec pluggable.sudoSu(account, 'redis-server --unixsocket ~/redis.sock --port 0 --daemonize yes'), (err) ->
|
||||
throw err if err
|
||||
app.redis.del 'rp:process_list', ->
|
||||
callback()
|
||||
else
|
||||
child_process.exec pluggable.sudoSu(account, "pkill -ef -u #{account.username} redis-server"), ->
|
||||
callback()
|
||||
|
||||
switch_status: (account, callback) ->
|
||||
monitor.getProcessList (plist) ->
|
||||
process = _.find plist, (i) ->
|
||||
return i.user == account.username and i.command.trim() == 'redis-server *:0'
|
||||
|
||||
callback if process then true else false
|
||||
Reference in New Issue
Block a user