shadowsocks-manager
Version:
A shadowsocks manager tool for multi user and traffic control.
1,018 lines (971 loc) • 31.9 kB
JavaScript
const knex = appRequire('init/knex').knex;
const serverManager = appRequire('plugins/flowSaver/server');
const manager = appRequire('services/manager');
const config = appRequire('services/config').all();
const macAccount = appRequire('plugins/macAccount/index');
const orderPlugin = appRequire('plugins/webgui_order');
const accountFlow = appRequire('plugins/account/accountFlow');
const webguiTag = appRequire('plugins/webgui_tag');
const redis = appRequire('init/redis').redis;
const crypto = require('crypto');
const getRandomPassword = passowrdLength => {
const passwordChars = '23456789ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz';
const password = Array(passowrdLength).fill(passwordChars).map(function(x) { return x[Math.floor(Math.random() * x.length)]; }).join('');
return password;
};
const runCommand = async cmd => {
const exec = require('child_process').exec;
return new Promise((resolve, reject) => {
exec(cmd, (err, stdout, stderr) => {
if(err) {
return reject(stderr);
} else {
return resolve(stdout);
}
});
});
};
const addAccount = async (type, options) => {
let key;
try {
const privateKey = await runCommand('wg genkey');
const publicKey = await runCommand(`echo '${ privateKey.trim() }' | wg pubkey`);
key = publicKey.trim() + ':' + privateKey.trim();
} catch(err) {}
if(!options.hasOwnProperty('active')) { options.active = 1; }
if(type === 6 || type === 7) {
type = 3;
}
const subscribeToken = crypto.randomBytes(16).toString('hex');
if(type === 1) {
const [ accountId ] = await knex('account_plugin').insert({
type,
orderId: 0,
userId: options.user,
port: options.port,
password: options.password,
data: options.flow > 0 ? JSON.stringify({
flow: options.flow,
}) : null,
status: 0,
server: options.server ? options.server : null,
autoRemove: 0,
multiServerFlow: options.multiServerFlow || 0,
key,
subscribe: subscribeToken,
});
await accountFlow.add(accountId);
return accountId;
} else if (type >= 2 && type <= 5) {
const [ accountId ] = await knex('account_plugin').insert({
type,
orderId: options.orderId || 0,
userId: options.user,
port: options.port,
password: options.password,
data: JSON.stringify({
create: options.time || Date.now(),
flow: options.flow || 1 * 1000 * 1000 * 1000,
limit: options.limit || 1,
}),
status: 0,
server: options.server ? options.server : null,
autoRemove: options.autoRemove || 0,
autoRemoveDelay: options.autoRemoveDelay || 0,
multiServerFlow: options.multiServerFlow || 0,
active: options.active,
key,
subscribe: subscribeToken,
});
await accountFlow.add(accountId);
return accountId;
}
};
const changePort = async (id, port) => {
const result = await knex('account_plugin').update({ port }).where({ id });
await accountFlow.edit(id);
};
const getAccount = async (options = {}) => {
const where = {};
if(options.id) {
where['account_plugin.id'] = options.id;
}
if(options.userId) {
where['user.id'] = options.userId;
}
if(options.port) {
where['account_plugin.port'] = options.port;
}
if(options.group >= 0) {
where['user.group'] = options.group;
}
const account = await knex('account_plugin').select([
'account_plugin.id',
'account_plugin.type',
'account_plugin.orderId',
'webgui_order.name as orderName',
'account_plugin.userId',
'account_plugin.server',
'account_plugin.port',
'account_plugin.password',
'account_plugin.key',
'account_plugin.data',
'account_plugin.status',
'account_plugin.autoRemove',
'account_plugin.autoRemoveDelay',
'account_plugin.multiServerFlow',
'account_plugin.active',
'user.id as userId',
'user.email as user',
])
.leftJoin('user', 'user.id', 'account_plugin.userId')
.leftJoin('webgui_order', 'webgui_order.id', 'account_plugin.orderId')
.where(where)
.orderBy('account_plugin.id', options.orderById ? 'desc' : 'asc');
return account;
};
const getOnlineAccount = async serverId => {
if(!serverId) {
const onlines = await knex('saveFlow').select([
'saveFlow.id as serverId',
]).countDistinct('saveFlow.accountId as online')
.where('saveFlow.time', '>', Date.now() - 5 * 60 * 1000)
.where('saveFlow.flow', '>', 10000)
.groupBy('saveFlow.id');
const result = {};
for(const online of onlines) {
result[online.serverId] = online.online;
};
return result;
}
const account = await knex('account_plugin').select([
'account_plugin.id',
'account_plugin.port',
])
.whereExists(
knex('saveFlow')
.where({ 'saveFlow.id': serverId })
.whereRaw('saveFlow.accountId = account_plugin.id')
.where('saveFlow.time', '>', Date.now() - 5 * 60 * 1000)
.where('saveFlow.flow', '>', 10000)
);
return account.map(m => m.id);
};
const delAccount = async id => {
const accountInfo = await knex('account_plugin').where({ id }).then(s => s[0]);
if(!accountInfo) {
return Promise.reject('Account id[' + id + '] not found');
}
const result = await knex('account_plugin').delete().where({ id });
const servers = await knex('server').where({});
servers.forEach(server => {
manager.send({
command: 'del',
port: accountInfo.port + server.shift,
}, {
host: server.host,
port: server.port,
password: server.password,
});
});
await accountFlow.del(id);
if (accountInfo.userId) {
await redis.setnx(`Account:${accountInfo.userId}`, `${accountInfo.port}:${accountInfo.password}`);
await redis.expire(`Account:${accountInfo.userId}`, 86400);
}
return result;
};
const editAccount = async (id, options) => {
const account = await knex('account_plugin').where({ id }).then(success => {
if(success.length) {
return success[0];
}
return Promise.reject('account not found');
});
const update = {};
if(options.hasOwnProperty('active')) { update.active = options.active; }
update.type = options.type;
update.orderId = options.orderId;
update.userId = options.userId;
update.autoRemove = options.autoRemove;
update.autoRemoveDelay = options.autoRemoveDelay;
update.multiServerFlow = options.multiServerFlow;
if(options.hasOwnProperty('server')) {
update.server = options.server ? JSON.stringify(options.server) : null;
}
if(options.type === 1) {
if(options.flow && options.flow > 0) {
update.data = JSON.stringify({
flow: options.flow,
});
} else {
update.data = null;
}
} else if(options.type >= 2 && options.type <= 5) {
update.data = JSON.stringify({
create: options.time || Date.now(),
flow: options.flow || 1 * 1000 * 1000 * 1000,
limit: options.limit || 1,
});
}
if(options.port) {
update.port = +options.port;
if(+options.port !== account.port) {
const servers = await knex('server').where({});
servers.forEach(server => {
manager.send({
command: 'del',
port: account.port + server.shift,
}, {
host: server.host,
port: server.port,
password: server.password,
});
});
}
}
await knex('account_plugin').update(update).where({ id });
await await accountFlow.edit(id);
return;
};
const editAccountTime = async (id, timeString, check) => {
const time = +timeString;
let accountInfo = await knex('account_plugin').where({ id }).then(s => s[0]);
if(accountInfo.type < 2 || accountInfo.type > 5) { return; }
accountInfo.data = JSON.parse(accountInfo.data);
const timePeriod = {
'2': 7 * 86400 * 1000,
'3': 30 * 86400 * 1000,
'4': 1 * 86400 * 1000,
'5': 3600 * 1000,
};
accountInfo.data.create += time;
while(time > 0 && accountInfo.data.create >= Date.now()) {
accountInfo.data.limit += 1;
accountInfo.data.create -= timePeriod[accountInfo.type];
}
await knex('account_plugin').update({
data: JSON.stringify(accountInfo.data)
}).where({ id });
await accountFlow.edit(id);
};
const editAccountTimeForRef = async (id, timeString, check) => {
const time = +timeString;
let accountInfo = await knex('account_plugin').where({ id }).then(s => s[0]);
if(accountInfo.type < 2 || accountInfo.type > 5) { return; }
accountInfo.data = JSON.parse(accountInfo.data);
const timePeriod = {
'2': 7 * 86400 * 1000,
'3': 30 * 86400 * 1000,
'4': 1 * 86400 * 1000,
'5': 3600 * 1000,
};
if(accountInfo.data.create + timePeriod[accountInfo.type] * accountInfo.data.limit <= Date.now()) {
accountInfo.data.limit = 1;
accountInfo.data.create = Date.now() + time - timePeriod[accountInfo.type];
} else {
accountInfo.data.create += time;
}
while(time > 0 && accountInfo.data.create >= Date.now()) {
accountInfo.data.limit += 1;
accountInfo.data.create -= timePeriod[accountInfo.type];
}
await knex('account_plugin').update({
data: JSON.stringify(accountInfo.data)
}).where({ id });
await accountFlow.edit(id);
};
const changePassword = async (id, password) => {
const account = await knex('account_plugin').select().where({ id }).then(success => {
if(success.length) {
return success[0];
}
return Promise.reject('account not found');
});
await knex('account_plugin').update({
password,
}).where({ id });
await accountFlow.pwd(id, password);
return;
};
const addAccountLimit = async (id, number = 1) => {
const account = await knex('account_plugin').select().where({ id }).then(success => {
if(success.length) {
return success[0];
}
return Promise.reject('account not found');
});
if(account.type < 2 || account.type > 5) { return; }
const accountData = JSON.parse(account.data);
const timePeriod = {
'2': 7 * 86400 * 1000,
'3': 30 * 86400 * 1000,
'4': 1 * 86400 * 1000,
'5': 3600 * 1000,
};
if(accountData.create + accountData.limit * timePeriod[account.type] <= Date.now()) {
accountData.create = Date.now();
accountData.limit = number;
} else {
accountData.limit += number;
}
await knex('account_plugin').update({
data: JSON.stringify(accountData),
}).where({ id });
return;
};
const addAccountLimitToMonth = async (userId, accountId, number = 1) => {
if(!accountId) {
const port = await knex('account_plugin').select()
.orderBy('port', 'DESC').limit(1)
.then(success => {
if(success.length) {
return success[0].port + 1;
} else {
return 50000;
}
});
await addAccount(3, {
user: userId,
port,
password: getRandomPassword(10),
time: Date.now(),
limit: number,
flow: 200 * 1000 * 1000 * 1000,
autoRemove: 0,
});
return;
}
const account = await knex('account_plugin').select().where({ id: accountId }).then(success => {
if(success.length) {
return success[0];
}
return Promise.reject('account not found');
});
if(account.type < 2 || account.type > 5) { return; }
const accountData = JSON.parse(account.data);
accountData.flow = 200 * 1000 * 1000 * 1000;
if(account.type === 3) {
if(accountData.create + accountData.limit * 30 * 86400 * 1000 <= Date.now()) {
accountData.create = Date.now();
accountData.limit = number;
} else {
accountData.limit += number;
}
} else {
const timePeriod = {
'2': 7 * 86400 * 1000,
'3': 30 * 86400 * 1000,
'4': 1 * 86400 * 1000,
'5': 3600 * 1000,
};
let expireTime = accountData.create + accountData.limit * timePeriod[account.type];
if(expireTime <= Date.now()) {
expireTime = 30 * 86400 * 1000 * number + Date.now();
} else {
expireTime += 30 * 86400 * 1000 * number;
}
accountData.create = expireTime;
accountData.limit = 0;
while(accountData.create >= Date.now()) {
accountData.limit += 1;
accountData.create -= 30 * 86400 * 1000;
}
}
await knex('account_plugin').update({
type: 3,
data: JSON.stringify(accountData),
autoRemove: 0,
}).where({ id: accountId });
return;
};
const setAccountLimit = async (userId, accountId, orderId) => {
const orderInfo = await orderPlugin.getOneOrder(orderId);
if(orderInfo.baseId) {
await knex('webgui_flow_pack').insert({
accountId,
flow: orderInfo.flow,
createTime: Date.now(),
});
await accountFlow.edit(accountId);
return;
}
const limit = orderInfo.cycle;
const orderType = orderInfo.type;
let account;
if(accountId) {
account = await knex('account_plugin').select().where({ id: accountId }).then(success => {
if(success.length) {
return success[0];
}
return null;
});
}
if(!accountId || !account) {
const getNewPort = () => {
let orderPorts = [];
if(orderInfo.portRange !== '0') {
try {
orderInfo.portRange.split(',').filter(f => f.trim()).forEach(f => {
if(f.indexOf('-')) {
const start = f.split('-').filter(f => f.trim())[0];
const end = f.split('-').filter(f => f.trim())[1];
if(start >= end) { return; }
for(let p = start; p <= end; p++) {
orderPorts.indexOf(p) >= 0 || orderPorts.push(p);
}
} else {
orderPorts.indexOf(+f) >= 0 || orderPorts.push(+f);
}
});
} catch(err) {
console.log(err);
}
}
return knex('webguiSetting').select().where({
key: 'account',
}).then(success => {
if(!success.length) { return Promise.reject('settings not found'); }
success[0].value = JSON.parse(success[0].value);
return success[0].value.port;
}).then(port => {
if(port.random) {
const getRandomPort = () => {
if(orderPorts.length) {
return orderPorts[Math.floor(Math.random() * orderPorts.length)];
} else {
return Math.floor(Math.random() * (port.end - port.start + 1) + port.start);
}
};
let retry = 0;
let myPort = getRandomPort();
const checkIfPortExists = port => {
let myPort = port;
return knex('account_plugin').select()
.where({ port }).then(success => {
if(success.length && retry <= 30) {
retry++;
myPort = getRandomPort();
return checkIfPortExists(myPort);
} else if (success.length && retry > 30) {
return Promise.reject('Can not get a random port');
} else {
return myPort;
}
});
};
return checkIfPortExists(myPort);
} else {
let query;
if(orderPorts.length) {
query = knex('account_plugin').select()
.whereIn('port', orderPorts)
.orderBy('port', 'ASC');
} else {
query = knex('account_plugin').select()
.whereBetween('port', [port.start, port.end])
.orderBy('port', 'ASC');
}
return query.then(success => {
const portArray = success.map(m => m.port);
let myPort;
if(orderPorts.length) {
for(const p of orderPorts) {
if(portArray.indexOf(+p) < 0) {
myPort = p; break;
}
}
} else {
for(let p = port.start; p <= port.end; p++) {
if(portArray.indexOf(+p) < 0) {
myPort = p; break;
}
}
}
if(myPort) {
return myPort;
} else {
return Promise.reject('no port');
}
});
}
});
};
const port = await getNewPort();
await addAccount(orderType, {
orderId,
user: userId,
port,
password: getRandomPassword(10),
time: Date.now(),
limit,
flow: orderInfo.flow,
server: orderInfo.server,
autoRemove: orderInfo.autoRemove ? 1 : 0,
autoRemoveDelay: orderInfo.autoRemoveDelay,
multiServerFlow: orderInfo.multiServerFlow ? 1 : 0,
active: orderInfo.active,
});
return;
}
const compareType = (current, order) => {
if(current === order) { return false; }
else if(current === 3) { return true; }
else if(current === 2 && order !== 3) { return true; }
else if(current === 4 && order === 5) { return true; }
else { return false; }
};
const onlyIncreaseTime = compareType(account.type, orderType);
if(onlyIncreaseTime) {
const accountData = JSON.parse(account.data);
const timePeriod = {
'2': 7 * 86400 * 1000,
'3': 30 * 86400 * 1000,
'4': 1 * 86400 * 1000,
'5': 3600 * 1000,
};
let expireTime = accountData.create + accountData.limit * timePeriod[account.type];
if(expireTime <= Date.now()) {
expireTime = timePeriod[orderType] * limit + Date.now();
} else {
expireTime += timePeriod[orderType] * limit;
}
let countTime = timePeriod[account.type];
accountData.create = expireTime - countTime;
accountData.limit = 1;
while(accountData.create >= Date.now()) {
accountData.limit += 1;
accountData.create -= countTime;
}
await knex('account_plugin').update({
data: JSON.stringify(accountData),
}).where({ id: accountId });
await accountFlow.edit(accountId);
return;
}
const accountData = JSON.parse(account.data);
accountData.flow = orderInfo.flow;
const timePeriod = {
'2': 7 * 86400 * 1000,
'3': 30 * 86400 * 1000,
'4': 1 * 86400 * 1000,
'5': 3600 * 1000,
};
let expireTime = accountData.create + accountData.limit * timePeriod[account.type];
if(expireTime <= Date.now()) {
expireTime = timePeriod[orderType] * limit + Date.now();
} else {
expireTime += timePeriod[orderType] * limit;
}
let countTime = timePeriod[orderType];
accountData.create = expireTime - countTime;
accountData.limit = 1;
while(accountData.create >= Date.now()) {
accountData.limit += 1;
accountData.create -= countTime;
}
// let port = await getAccount({ id: accountId }).then(success => success[0].port);
await knex('account_plugin').update({
type: orderType,
orderId,
data: JSON.stringify(accountData),
server: orderInfo.server,
autoRemove: orderInfo.autoRemove ? 1 : 0,
multiServerFlow: orderInfo.multiServerFlow ? 1 : 0,
}).where({ id: accountId });
await accountFlow.edit(accountId);
return;
};
const addAccountTime = async (userId, accountId, accountType, accountPeriod = 1) => {
// type: 2 周 ,3 月, 4 天, 5 小时
const getTimeByType = type => {
const time = {
'2': 7 * 24 * 60 * 60 * 1000,
'3': 30 * 24 * 60 * 60 * 1000,
'4': 24 * 60 * 60 * 1000,
'5': 60 * 60 * 1000,
};
return time[type];
};
const paymentInfo = await knex('webguiSetting').select().where({
key: 'payment',
}).then(success => {
if(!success.length) {
return Promise.reject('settings not found');
}
success[0].value = JSON.parse(success[0].value);
return success[0].value;
});
const getPaymentInfo = type => {
const pay = {
'2': 'week',
'3': 'month',
'4': 'day',
'5': 'hour',
};
return paymentInfo[pay[type]];
};
const checkIfAccountExists = async (accountId) => {
if(!accountId) { return null; }
const account = await knex('account_plugin').where({ id: accountId });
if(!account.length) { return null; }
const accountInfo = account[0];
accountInfo.data = JSON.parse(account[0].data);
return accountInfo;
};
const accountInfo = await checkIfAccountExists(accountId);
if(!accountInfo) {
const getNewPort = async () => {
const port = await knex('webguiSetting').select().where({
key: 'account',
}).then(success => {
if(!success.length) { return Promise.reject('settings not found'); }
success[0].value = JSON.parse(success[0].value);
return success[0].value.port;
});
if(port.random) {
const getRandomPort = () => Math.floor(Math.random() * (port.end - port.start + 1) + port.start);
let retry = 0;
let myPort = getRandomPort();
const checkIfPortExists = port => {
let myPort = port;
return knex('account_plugin').select()
.where({ port }).then(success => {
if(success.length && retry <= 30) {
retry++;
myPort = getRandomPort();
return checkIfPortExists(myPort);
} else if (success.length && retry > 30) {
return Promise.reject('Can not get a random port');
} else {
return myPort;
}
});
};
return checkIfPortExists(myPort);
} else {
return knex('account_plugin').select()
.whereBetween('port', [port.start, port.end])
.orderBy('port', 'DESC').limit(1).then(success => {
if(success.length) {
return success[0].port + 1;
}
return port.start;
});
}
};
const port = await getNewPort();
const subscribeToken = crypto.randomBytes(16).toString('hex');
await knex('account_plugin').insert({
type: accountType,
userId,
server: getPaymentInfo(accountType).server ? JSON.stringify(getPaymentInfo(accountType).server) : null,
port,
password: getRandomPassword(10),
data: JSON.stringify({
create: Date.now(),
flow: getPaymentInfo(accountType).flow * 1000 * 1000,
limit: accountPeriod,
}),
autoRemove: getPaymentInfo(accountType).autoRemove,
multiServerFlow: getPaymentInfo(accountType).multiServerFlow,
subscribe: subscribeToken,
});
return;
}
let onlyIncreaseTime = false;
if(accountInfo.type === 3 && accountType !== 3) { onlyIncreaseTime = true; }
if(accountInfo.type === 2 && (accountType === 4 || accountType === 5)) { onlyIncreaseTime = true; }
if(accountInfo.type === 4 && accountType === 5) { onlyIncreaseTime = true; }
const isAccountOutOfDate = accountInfo => {
const expire = accountInfo.data.create + accountInfo.data.limit * getTimeByType(accountInfo.type);
return expire <= Date.now();
};
if(onlyIncreaseTime) {
let expireTime;
if(isAccountOutOfDate(accountInfo)) {
expireTime = Date.now() + getTimeByType(accountType) * accountPeriod;
} else {
expireTime = accountInfo.data.create + getTimeByType(accountInfo.type) * accountInfo.data.limit + getTimeByType(accountType) * accountPeriod;
}
let createTime = expireTime - getTimeByType(accountInfo.type);
let limit = 1;
while(createTime >= Date.now()) {
limit += 1;
createTime -= getTimeByType(accountInfo.type);
}
await knex('account_plugin').update({
data: JSON.stringify({
create: createTime,
flow: accountInfo.data.flow,
limit,
}),
}).where({ id: accountId });
return;
}
let expireTime;
if(isAccountOutOfDate(accountInfo)) {
expireTime = Date.now() + getTimeByType(accountType) * accountPeriod;
} else {
expireTime = accountInfo.data.create + getTimeByType(accountInfo.type) * accountInfo.data.limit + getTimeByType(accountType) * accountPeriod;
}
let createTime = expireTime - getTimeByType(accountType);
let limit = 1;
while(createTime >= Date.now()) {
limit += 1;
createTime -= getTimeByType(accountType);
}
await knex('account_plugin').update({
type: accountType,
server: getPaymentInfo(accountType).server ? JSON.stringify(getPaymentInfo(accountType).server) : null,
data: JSON.stringify({
create: createTime,
flow: getPaymentInfo(accountType).flow * 1000 * 1000,
limit,
}),
autoRemove: getPaymentInfo(accountType).autoRemove,
multiServerFlow: getPaymentInfo(accountType).multiServerFlow,
}).where({ id: accountId });
return;
};
const banAccount = async options => {
const serverId = options.serverId;
const accountId = options.accountId;
const time = options.time;
await knex('account_flow').update({
status: 'ban',
nextCheckTime: Date.now(),
autobanTime: Date.now() + time,
}).where({
serverId, accountId,
});
};
const getBanAccount = async options => {
const serverId = options.serverId;
const accountId = options.accountId;
const accountInfo = await knex('account_flow').select([
'autobanTime as banTime'
]).where({
serverId, accountId, status: 'ban'
});
if(!accountInfo.length) { return { banTime: 0 }; }
return accountInfo[0];
};
const loginLog = {};
const scanLoginLog = ip => {
for(let i in loginLog) {
if(Date.now() - loginLog[i].time >= 10 * 60 * 1000) {
delete loginLog[i];
}
}
if(!loginLog[ip]) {
return false;
} else if (loginLog[ip].mac.length <= 10) {
return false;
} else {
return true;
}
};
const loginFail = (mac, ip) => {
if(!loginLog[ip]) {
loginLog[ip] = { mac: [ mac ], time: Date.now() };
} else {
if(loginLog[ip].mac.indexOf(mac) < 0) {
loginLog[ip].mac.push(mac);
loginLog[ip].time = Date.now();
}
}
};
const getAccountForSubscribe = async (token, ip) => {
if(scanLoginLog(ip)) {
return Promise.reject('ip is in black list');
}
const account = await knex('account_plugin').where({
subscribe: token
}).then(s => s[0]);
if(!account) {
loginFail(token, ip);
return Promise.reject('can not find account');
}
if(account.data) {
account.data = JSON.parse(account.data);
} else {
account.data = {};
}
if(account.server) {
account.server = JSON.parse(account.server);
}
const servers = await serverManager.list({ status: false });
const validServers = [];
for(const server of servers) {
const tags = await webguiTag.getTags('server', server.id);
if(tags.includes('#_hide') || tags.includes('#hide')) {
continue;
}
if(!account.server || account.server.includes(server.id)) {
validServers.push(server);
continue;
}
}
return { server: validServers, account };
};
const sleep = time => new Promise(resolve => setTimeout(resolve, time));
const editMultiAccounts = async (orderId, update) => {
const accounts = await knex('account_plugin').where({ orderId });
const updateData = {};
for(const account of accounts) {
if(update.hasOwnProperty('flow')) {
const accountData = JSON.parse(account.data);
accountData.flow = update.flow;
updateData.data = JSON.stringify(accountData);
}
if(update.hasOwnProperty('server')) {
updateData.server = update.server ? JSON.stringify(update.server): null;
}
if(update.hasOwnProperty('autoRemove')) {
updateData.autoRemove = update.autoRemove;
}
if(Object.keys(updateData).length === 0) { break; }
await knex('account_plugin').update(updateData).where({ id: account.id });
await accountFlow.edit(account.id);
await sleep(500);
}
};
const activeAccount = async accountId => {
const accountInfo = await getAccount({ id: accountId }).then(s => s[0]);
await knex('account_plugin').update({ active: 1 }).where({ id: accountInfo.id });
await accountFlow.edit(accountInfo.id);
if(accountInfo.type > 1) {
const accountData = JSON.parse(accountInfo.data);
accountData.create = Date.now();
await knex('account_plugin').update({ data: JSON.stringify(accountData) }).where({ id: accountInfo.id });
}
};
const getAccountAndPaging = async (opt) => {
const search = opt.search || '';
const page = opt.page || 1;
const pageSize = opt.pageSize || 20;
const sort = opt.sort || 'port_asc';
const filter = opt.filter;
const where = {};
if(filter.orderId) {
where['account_plugin.orderId'] = +filter.orderId;
}
let account = knex('account_plugin').select([
'account_plugin.id',
'account_plugin.type',
'account_plugin.orderId',
'account_plugin.userId',
'account_plugin.server',
'account_plugin.port',
'account_plugin.password',
'account_plugin.key',
'account_plugin.data',
'account_plugin.status',
'account_plugin.autoRemove',
'account_plugin.autoRemoveDelay',
'account_plugin.multiServerFlow',
'account_plugin.active',
'user.id as userId',
'user.email as user',
])
.leftJoin('user', 'user.id', 'account_plugin.userId')
.orderBy('account_plugin.port', 'ASC')
.where(where);
if(!filter.hasUser && filter.noUser) {
account = await account.whereNull('user.id');
} else if(filter.hasUser && !filter.noUser) {
account = await account.whereNotNull('user.id');
} else {
account = await account;
}
account.forEach(a => {
if(a.data) {
a.data = JSON.parse(a.data);
const time = {
'2': 7 * 24 * 3600000,
'3': 30 * 24 * 3600000,
'4': 24 * 3600000,
'5': 3600000,
};
a.data.expire = a.data.create + a.data.limit * time[a.type];
}
});
if(filter.mac) {
const macAccounts = await macAccount.getAllAccount();
account.splice(account.length, 0, ...macAccounts);
}
if(search) {
account = account.filter(f => {
return (
(f.user && f.user.toLowerCase().includes(search.toLowerCase())) ||
(f.port && f.port.toString().includes(search)) ||
(f.password && f.password.includes(search)) ||
(f.mac && f.mac.includes(search))
);
});
}
account = account.filter(f => {
let show = true;
if(!filter.unlimit && f.type === 1) {
show = false;
}
if(!filter.expired && f.data && f.data.expire >= Date.now()) {
show = false;
}
if(!filter.unexpired && f.data && f.data.expire <= Date.now()) {
show = false;
}
return show;
});
account = account.sort((a, b) => {
if(a.mac && !b.mac) {
return 1;
} else if(!a.mac && b.mac) {
return -1;
} else if(sort === 'port_asc') {
return a.port >= b.port ? 1 : -1;
} else if (sort === 'port_desc') {
return a.port <= b.port ? 1 : -1;
} else if (sort === 'expire_desc') {
if(!a.data) { return -1; }
if(!b.data) { return 1; }
return a.data.expire <= b.data.expire ? 1 : -1;
} else if (sort === 'expire_asc') {
if(!a.data) { return 1; }
if(!b.data) { return -1; }
return a.data.expire >= b.data.expire ? 1 : -1;
}
});
const count = account.length;
const start = pageSize * (page - 1);
const end = start + pageSize;
const result = account.slice(start, end);
const maxPage = Math.ceil(count / pageSize);
return {
total: count,
page,
maxPage,
pageSize,
account: result,
};
};
exports.addAccount = addAccount;
exports.getAccount = getAccount;
exports.delAccount = delAccount;
exports.editAccount = editAccount;
exports.editAccountTime = editAccountTime;
exports.editAccountTimeForRef = editAccountTimeForRef;
exports.changePassword = changePassword;
exports.changePort = changePort;
exports.addAccountLimit = addAccountLimit;
exports.addAccountLimitToMonth = addAccountLimitToMonth;
exports.setAccountLimit = setAccountLimit;
exports.addAccountTime = addAccountTime;
exports.banAccount = banAccount;
exports.getBanAccount = getBanAccount;
exports.getAccountForSubscribe = getAccountForSubscribe;
exports.editMultiAccounts = editMultiAccounts;
exports.activeAccount = activeAccount;
exports.getOnlineAccount = getOnlineAccount;
exports.getAccountAndPaging = getAccountAndPaging;