init
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package trojan
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"trojan/core"
|
||||
"trojan/util"
|
||||
)
|
||||
|
||||
var clientPath = "/root/config.json"
|
||||
|
||||
// GenClientJson 生成客户端json
|
||||
func GenClientJson() {
|
||||
fmt.Println()
|
||||
var user core.User
|
||||
domain, port := GetDomainAndPort()
|
||||
mysql := core.GetMysql()
|
||||
userList, err := mysql.GetData()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
if len(userList) == 1 {
|
||||
user = *userList[0]
|
||||
} else {
|
||||
UserList()
|
||||
choice := util.LoopInput("请选择要生成配置文件的用户序号: ", userList, true)
|
||||
if choice < 0 {
|
||||
return
|
||||
}
|
||||
user = *userList[choice-1]
|
||||
}
|
||||
pass, err := base64.StdEncoding.DecodeString(user.Password)
|
||||
if err != nil {
|
||||
fmt.Println(util.Red("Base64解码失败: " + err.Error()))
|
||||
return
|
||||
}
|
||||
if !core.WriteClient(port, string(pass), domain, clientPath) {
|
||||
fmt.Println(util.Red("生成配置文件失败!"))
|
||||
} else {
|
||||
fmt.Println("成功生成配置文件: " + util.Green(clientPath))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package trojan
|
||||
|
||||
var (
|
||||
// MVersion 程序版本号
|
||||
MVersion string
|
||||
// BuildDate 编译时间
|
||||
BuildDate string
|
||||
// GoVersion go版本
|
||||
GoVersion string
|
||||
// GitVersion git版本
|
||||
GitVersion string
|
||||
)
|
||||
@@ -0,0 +1,224 @@
|
||||
package trojan
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"trojan/asset"
|
||||
"trojan/core"
|
||||
"trojan/util"
|
||||
)
|
||||
|
||||
var (
|
||||
dockerInstallUrl = "https://docker-install.netlify.app/install.sh"
|
||||
dbDockerRun = "docker run --name trojan-mariadb --restart=always -p %d:3306 -v /home/mariadb:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=%s -e MYSQL_ROOT_HOST=%% -e MYSQL_DATABASE=trojan -d mariadb:10.2"
|
||||
)
|
||||
|
||||
// InstallMenu 安装目录
|
||||
func InstallMenu() {
|
||||
fmt.Println()
|
||||
menu := []string{"更新trojan", "证书申请", "安装mysql"}
|
||||
switch util.LoopInput("请选择: ", menu, true) {
|
||||
case 1:
|
||||
InstallTrojan("")
|
||||
case 2:
|
||||
InstallTls()
|
||||
case 3:
|
||||
InstallMysql()
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// InstallDocker 安装docker
|
||||
func InstallDocker() {
|
||||
if !util.CheckCommandExists("docker") {
|
||||
util.RunWebShell(dockerInstallUrl)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// InstallTrojan 安装trojan
|
||||
func InstallTrojan(version string) {
|
||||
fmt.Println()
|
||||
data := string(asset.GetAsset("trojan-install.sh"))
|
||||
checkTrojan := util.ExecCommandWithResult("systemctl list-unit-files|grep trojan.service")
|
||||
if (checkTrojan == "" && runtime.GOARCH != "amd64") || Type() == "trojan-go" {
|
||||
data = strings.ReplaceAll(data, "TYPE=0", "TYPE=1")
|
||||
}
|
||||
if version != "" {
|
||||
data = strings.ReplaceAll(data, "INSTALL_VERSION=\"\"", "INSTALL_VERSION=\""+version+"\"")
|
||||
}
|
||||
util.ExecCommand(data)
|
||||
util.OpenPort(443)
|
||||
util.SystemctlRestart("trojan")
|
||||
util.SystemctlEnable("trojan")
|
||||
}
|
||||
|
||||
// InstallTls 安装证书
|
||||
func InstallTls() {
|
||||
domain := ""
|
||||
server := "letsencrypt"
|
||||
fmt.Println()
|
||||
choice := util.LoopInput("请选择使用证书方式: ", []string{"Let's Encrypt 证书", "ZeroSSL 证书", "BuyPass 证书", "自定义证书路径"}, true)
|
||||
if choice < 0 {
|
||||
return
|
||||
} else if choice == 4 {
|
||||
crtFile := util.Input("请输入证书的cert文件路径: ", "")
|
||||
keyFile := util.Input("请输入证书的key文件路径: ", "")
|
||||
if !util.IsExists(crtFile) || !util.IsExists(keyFile) {
|
||||
fmt.Println("输入的cert或者key文件不存在!")
|
||||
} else {
|
||||
domain = util.Input("请输入此证书对应的域名: ", "")
|
||||
if domain == "" {
|
||||
fmt.Println("输入域名为空!")
|
||||
return
|
||||
}
|
||||
core.WriteTls(crtFile, keyFile, domain)
|
||||
}
|
||||
} else {
|
||||
if choice == 2 {
|
||||
server = "zerossl"
|
||||
} else if choice == 3 {
|
||||
server = "buypass"
|
||||
}
|
||||
localIP := util.GetLocalIP()
|
||||
fmt.Printf("本机ip: %s\n", localIP)
|
||||
for {
|
||||
domain = util.Input("请输入申请证书的域名: ", "")
|
||||
ipList, err := net.LookupIP(domain)
|
||||
fmt.Printf("%s 解析到的ip: %v\n", domain, ipList)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println("域名有误,请重新输入")
|
||||
continue
|
||||
}
|
||||
checkIp := false
|
||||
for _, ip := range ipList {
|
||||
if localIP == ip.String() {
|
||||
checkIp = true
|
||||
}
|
||||
}
|
||||
if checkIp {
|
||||
break
|
||||
} else {
|
||||
fmt.Println("输入的域名和本机ip不一致, 请重新输入!")
|
||||
}
|
||||
}
|
||||
util.InstallPack("socat")
|
||||
if !util.IsExists("/root/.acme.sh/acme.sh") {
|
||||
util.RunWebShell("https://get.acme.sh")
|
||||
}
|
||||
util.SystemctlStop("trojan-web")
|
||||
util.OpenPort(80)
|
||||
checkResult := util.ExecCommandWithResult("/root/.acme.sh/acme.sh -v|tr -cd '[0-9]'")
|
||||
acmeVersion, _ := strconv.Atoi(checkResult)
|
||||
if acmeVersion < 300 {
|
||||
util.ExecCommand("/root/.acme.sh/acme.sh --upgrade")
|
||||
}
|
||||
if server != "letsencrypt" {
|
||||
var email string
|
||||
for {
|
||||
email = util.Input(fmt.Sprintf("请输入申请%s域名所需的邮箱: ", server), "")
|
||||
if email == "" {
|
||||
fmt.Println("申请域名的邮箱地址为空!")
|
||||
return
|
||||
} else if util.VerifyEmailFormat(email) {
|
||||
break
|
||||
} else {
|
||||
fmt.Println("邮箱格式不正确, 请重新输入!")
|
||||
}
|
||||
}
|
||||
util.ExecCommand(fmt.Sprintf("bash /root/.acme.sh/acme.sh --server %s --register-account -m %s", server, email))
|
||||
}
|
||||
issueCommand := fmt.Sprintf("bash /root/.acme.sh/acme.sh --issue -d %s --debug --standalone --keylength ec-256 --force --server %s", domain, server)
|
||||
if server == "buypass" {
|
||||
issueCommand = issueCommand + " --days 170"
|
||||
}
|
||||
util.ExecCommand(issueCommand)
|
||||
crtFile := "/root/.acme.sh/" + domain + "_ecc" + "/fullchain.cer"
|
||||
keyFile := "/root/.acme.sh/" + domain + "_ecc" + "/" + domain + ".key"
|
||||
core.WriteTls(crtFile, keyFile, domain)
|
||||
}
|
||||
Restart()
|
||||
util.SystemctlRestart("trojan-web")
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// InstallMysql 安装mysql
|
||||
func InstallMysql() {
|
||||
var (
|
||||
mysql core.Mysql
|
||||
choice int
|
||||
)
|
||||
fmt.Println()
|
||||
if util.IsExists("/.dockerenv") {
|
||||
choice = 2
|
||||
} else {
|
||||
choice = util.LoopInput("请选择: ", []string{"安装docker版mysql(mariadb)", "输入自定义mysql连接"}, true)
|
||||
}
|
||||
if choice < 0 {
|
||||
return
|
||||
} else if choice == 1 {
|
||||
mysql = core.Mysql{ServerAddr: "127.0.0.1", ServerPort: util.RandomPort(), Password: util.RandString(8, util.LETTER+util.DIGITS), Username: "root", Database: "trojan"}
|
||||
InstallDocker()
|
||||
fmt.Println(fmt.Sprintf(dbDockerRun, mysql.ServerPort, mysql.Password))
|
||||
if util.CheckCommandExists("setenforce") {
|
||||
util.ExecCommand("setenforce 0")
|
||||
}
|
||||
util.OpenPort(mysql.ServerPort)
|
||||
util.ExecCommand(fmt.Sprintf(dbDockerRun, mysql.ServerPort, mysql.Password))
|
||||
db := mysql.GetDB()
|
||||
for {
|
||||
fmt.Printf("%s mariadb启动中,请稍等...\n", time.Now().Format("2006-01-02 15:04:05"))
|
||||
err := db.Ping()
|
||||
if err == nil {
|
||||
db.Close()
|
||||
break
|
||||
} else {
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
fmt.Println("mariadb启动成功!")
|
||||
} else if choice == 2 {
|
||||
mysql = core.Mysql{}
|
||||
for {
|
||||
for {
|
||||
mysqlUrl := util.Input("请输入mysql连接地址(格式: host:port), 默认连接地址为127.0.0.1:3306, 使用直接回车, 否则输入自定义连接地址: ",
|
||||
"127.0.0.1:3306")
|
||||
urlInfo := strings.Split(mysqlUrl, ":")
|
||||
if len(urlInfo) != 2 {
|
||||
fmt.Printf("输入的%s不符合匹配格式(host:port)\n", mysqlUrl)
|
||||
continue
|
||||
}
|
||||
port, err := strconv.Atoi(urlInfo[1])
|
||||
if err != nil {
|
||||
fmt.Printf("%s不是数字\n", urlInfo[1])
|
||||
continue
|
||||
}
|
||||
mysql.ServerAddr, mysql.ServerPort = urlInfo[0], port
|
||||
break
|
||||
}
|
||||
mysql.Username = util.Input("请输入mysql的用户名(回车使用root): ", "root")
|
||||
mysql.Password = util.Input(fmt.Sprintf("请输入mysql %s用户的密码: ", mysql.Username), "")
|
||||
db := mysql.GetDB()
|
||||
if db != nil && db.Ping() == nil {
|
||||
mysql.Database = util.Input("请输入使用的数据库名(不存在可自动创建, 回车使用trojan): ", "trojan")
|
||||
db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s;", mysql.Database))
|
||||
break
|
||||
} else {
|
||||
fmt.Println("连接mysql失败, 请重新输入")
|
||||
}
|
||||
}
|
||||
}
|
||||
mysql.CreateTable()
|
||||
core.WriteMysql(&mysql)
|
||||
if userList, _ := mysql.GetData(); len(userList) == 0 {
|
||||
AddUser()
|
||||
}
|
||||
Restart()
|
||||
fmt.Println()
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package trojan
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"trojan/core"
|
||||
"trojan/util"
|
||||
)
|
||||
|
||||
// ControlMenu Trojan控制菜单
|
||||
func ControlMenu() {
|
||||
fmt.Println()
|
||||
tType := Type()
|
||||
if tType == "trojan" {
|
||||
tType = "trojan-go"
|
||||
} else {
|
||||
tType = "trojan"
|
||||
}
|
||||
menu := []string{"启动trojan", "停止trojan", "重启trojan", "查看trojan状态", "查看trojan日志", "修改trojan端口"}
|
||||
menu = append(menu, "切换为"+tType)
|
||||
switch util.LoopInput("请选择: ", menu, true) {
|
||||
case 1:
|
||||
Start()
|
||||
case 2:
|
||||
Stop()
|
||||
case 3:
|
||||
Restart()
|
||||
case 4:
|
||||
Status(true)
|
||||
case 5:
|
||||
go util.Log("trojan", 300)
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, os.Kill)
|
||||
//阻塞
|
||||
<-c
|
||||
case 6:
|
||||
ChangePort()
|
||||
case 7:
|
||||
if err := SwitchType(tType); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restart 重启trojan
|
||||
func Restart() {
|
||||
util.OpenPort(core.GetConfig().LocalPort)
|
||||
util.SystemctlRestart("trojan")
|
||||
}
|
||||
|
||||
// Start 启动trojan
|
||||
func Start() {
|
||||
util.OpenPort(core.GetConfig().LocalPort)
|
||||
util.SystemctlStart("trojan")
|
||||
}
|
||||
|
||||
// Stop 停止trojan
|
||||
func Stop() {
|
||||
util.SystemctlStop("trojan")
|
||||
}
|
||||
|
||||
// Status 获取trojan状态
|
||||
func Status(isPrint bool) string {
|
||||
result := util.SystemctlStatus("trojan")
|
||||
if isPrint {
|
||||
fmt.Println(result)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// UpTime Trojan运行时间
|
||||
func UpTime() string {
|
||||
result := strings.TrimSpace(util.ExecCommandWithResult("ps -Ao etime,args|grep -v grep|grep /usr/local/etc/trojan/config.json"))
|
||||
resultSlice := strings.Split(result, " ")
|
||||
if len(resultSlice) > 0 {
|
||||
return resultSlice[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ChangePort 修改trojan端口
|
||||
func ChangePort() {
|
||||
config := core.GetConfig()
|
||||
oldPort := config.LocalPort
|
||||
randomPort := util.RandomPort()
|
||||
fmt.Println("当前trojan端口: " + util.Green(strconv.Itoa(oldPort)))
|
||||
newPortStr := util.Input(fmt.Sprintf("请输入新的trojan端口(若要使用随机端口%s直接回车即可): ", util.Blue(strconv.Itoa(randomPort))), strconv.Itoa(randomPort))
|
||||
newPort, err := strconv.Atoi(newPortStr)
|
||||
if err != nil {
|
||||
fmt.Println("修改端口失败: " + err.Error())
|
||||
return
|
||||
}
|
||||
if core.WritePort(newPort) {
|
||||
util.OpenPort(newPort)
|
||||
fmt.Println(util.Green("端口修改成功!"))
|
||||
Restart()
|
||||
} else {
|
||||
fmt.Println(util.Red("端口修改成功!"))
|
||||
}
|
||||
}
|
||||
|
||||
// Version Trojan版本
|
||||
func Version() string {
|
||||
flag := "-v"
|
||||
if Type() == "trojan-go" {
|
||||
flag = "-version"
|
||||
}
|
||||
result := strings.TrimSpace(util.ExecCommandWithResult("/usr/bin/trojan/trojan " + flag))
|
||||
if len(result) == 0 {
|
||||
return ""
|
||||
}
|
||||
firstLine := strings.Split(result, "\n")[0]
|
||||
tempSlice := strings.Split(firstLine, " ")
|
||||
return tempSlice[len(tempSlice)-1]
|
||||
}
|
||||
|
||||
// SwitchType 切换Trojan类型
|
||||
func SwitchType(tType string) error {
|
||||
ARCH := runtime.GOARCH
|
||||
if ARCH != "amd64" && ARCH != "arm64" {
|
||||
return errors.New("not support " + ARCH + " machine")
|
||||
}
|
||||
if tType == "trojan" && ARCH != "amd64" {
|
||||
return errors.New("trojan not support " + ARCH + " machine")
|
||||
}
|
||||
if err := core.SetValue("trojanType", tType); err != nil {
|
||||
return err
|
||||
}
|
||||
InstallTrojan("")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type Trojan类型
|
||||
func Type() string {
|
||||
tType, _ := core.GetValue("trojanType")
|
||||
if tType == "" {
|
||||
if strings.Contains(Status(false), "trojan-go") {
|
||||
tType = "trojan-go"
|
||||
} else {
|
||||
tType = "trojan"
|
||||
}
|
||||
_ = core.SetValue("trojanType", tType)
|
||||
}
|
||||
return tType
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package trojan
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"trojan/core"
|
||||
"trojan/util"
|
||||
)
|
||||
|
||||
// UserMenu 用户管理菜单
|
||||
func UserMenu() {
|
||||
fmt.Println()
|
||||
menu := []string{"新增用户", "删除用户", "限制流量", "清空流量", "设置限期", "取消限期"}
|
||||
switch util.LoopInput("请选择: ", menu, false) {
|
||||
case 1:
|
||||
AddUser()
|
||||
case 2:
|
||||
DelUser()
|
||||
case 3:
|
||||
SetUserQuota()
|
||||
case 4:
|
||||
CleanData()
|
||||
case 5:
|
||||
SetupExpire()
|
||||
case 6:
|
||||
CancelExpire()
|
||||
}
|
||||
}
|
||||
|
||||
// AddUser 添加用户
|
||||
func AddUser() {
|
||||
randomUser := util.RandString(4, util.LETTER)
|
||||
randomPass := util.RandString(8, util.LETTER+util.DIGITS)
|
||||
inputUser := util.Input(fmt.Sprintf("生成随机用户名: %s, 使用直接回车, 否则输入自定义用户名: ", randomUser), randomUser)
|
||||
if inputUser == "admin" {
|
||||
fmt.Println(util.Yellow("不能新建用户名为'admin'的用户!"))
|
||||
return
|
||||
}
|
||||
mysql := core.GetMysql()
|
||||
if user := mysql.GetUserByName(inputUser); user != nil {
|
||||
fmt.Println(util.Yellow("已存在用户名为: " + inputUser + " 的用户!"))
|
||||
return
|
||||
}
|
||||
inputPass := util.Input(fmt.Sprintf("生成随机密码: %s, 使用直接回车, 否则输入自定义密码: ", randomPass), randomPass)
|
||||
base64Pass := base64.StdEncoding.EncodeToString([]byte(inputPass))
|
||||
if user := mysql.GetUserByPass(base64Pass); user != nil {
|
||||
fmt.Println(util.Yellow("已存在密码为: " + inputPass + " 的用户!"))
|
||||
return
|
||||
}
|
||||
if mysql.CreateUser(inputUser, base64Pass, inputPass) == nil {
|
||||
fmt.Println("新增用户成功!")
|
||||
}
|
||||
}
|
||||
|
||||
// DelUser 删除用户
|
||||
func DelUser() {
|
||||
userList := UserList()
|
||||
mysql := core.GetMysql()
|
||||
choice := util.LoopInput("请选择要删除的用户序号: ", userList, true)
|
||||
if choice == -1 {
|
||||
return
|
||||
}
|
||||
if mysql.DeleteUser(userList[choice-1].ID) == nil {
|
||||
fmt.Println("删除用户成功!")
|
||||
Restart()
|
||||
}
|
||||
}
|
||||
|
||||
// SetUserQuota 限制用户流量
|
||||
func SetUserQuota() {
|
||||
var (
|
||||
limit int
|
||||
err error
|
||||
)
|
||||
userList := UserList()
|
||||
mysql := core.GetMysql()
|
||||
choice := util.LoopInput("请选择要限制流量的用户序号: ", userList, true)
|
||||
if choice == -1 {
|
||||
return
|
||||
}
|
||||
for {
|
||||
quota := util.Input("请输入用户"+userList[choice-1].Username+"限制的流量大小(单位byte)", "")
|
||||
limit, err = strconv.Atoi(quota)
|
||||
if err != nil {
|
||||
fmt.Printf("%s 不是数字, 请重新输入!\n", quota)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if mysql.SetQuota(userList[choice-1].ID, limit) == nil {
|
||||
fmt.Println("成功设置用户" + userList[choice-1].Username + "限制流量" + util.Bytefmt(uint64(limit)))
|
||||
}
|
||||
}
|
||||
|
||||
// CleanData 清空用户流量
|
||||
func CleanData() {
|
||||
userList := UserList()
|
||||
mysql := core.GetMysql()
|
||||
choice := util.LoopInput("请选择要清空流量的用户序号: ", userList, true)
|
||||
if choice == -1 {
|
||||
return
|
||||
}
|
||||
if mysql.CleanData(userList[choice-1].ID) == nil {
|
||||
fmt.Println("清空流量成功!")
|
||||
}
|
||||
}
|
||||
|
||||
// CancelExpire 取消限期
|
||||
func CancelExpire() {
|
||||
userList := UserList()
|
||||
mysql := core.GetMysql()
|
||||
choice := util.LoopInput("请选择要取消限期的用户序号: ", userList, true)
|
||||
if choice == -1 {
|
||||
return
|
||||
}
|
||||
if userList[choice-1].UseDays == 0 {
|
||||
fmt.Println(util.Yellow("选择的用户未设置限期!"))
|
||||
return
|
||||
}
|
||||
if mysql.CancelExpire(userList[choice-1].ID) == nil {
|
||||
fmt.Println("取消限期成功!")
|
||||
}
|
||||
}
|
||||
|
||||
// SetupExpire 设置限期
|
||||
func SetupExpire() {
|
||||
userList := UserList()
|
||||
mysql := core.GetMysql()
|
||||
choice := util.LoopInput("请选择要设置限期的用户序号: ", userList, true)
|
||||
if choice == -1 {
|
||||
return
|
||||
}
|
||||
useDayStr := util.Input("请输入要限制使用的天数: ", "")
|
||||
if useDayStr == "" {
|
||||
return
|
||||
} else if strings.Contains(useDayStr, "-") {
|
||||
fmt.Println(util.Yellow("天数不能为负数"))
|
||||
return
|
||||
} else if !util.IsInteger(useDayStr) {
|
||||
fmt.Println(util.Yellow("输入为非整数!"))
|
||||
return
|
||||
}
|
||||
useDays, _ := strconv.Atoi(useDayStr)
|
||||
if mysql.SetExpire(userList[choice-1].ID, uint(useDays)) == nil {
|
||||
fmt.Println("设置限期成功!")
|
||||
}
|
||||
}
|
||||
|
||||
// CleanDataByName 清空指定用户流量
|
||||
func CleanDataByName(usernames []string) {
|
||||
mysql := core.GetMysql()
|
||||
if err := mysql.CleanDataByName(usernames); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
} else {
|
||||
fmt.Println("清空流量成功!")
|
||||
}
|
||||
}
|
||||
|
||||
// UserList 获取用户列表并打印显示
|
||||
func UserList(ids ...string) []*core.User {
|
||||
mysql := core.GetMysql()
|
||||
userList, err := mysql.GetData(ids...)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return nil
|
||||
}
|
||||
domain, port := GetDomainAndPort()
|
||||
for i, k := range userList {
|
||||
pass, err := base64.StdEncoding.DecodeString(k.Password)
|
||||
if err != nil {
|
||||
pass = []byte("")
|
||||
}
|
||||
fmt.Printf("%d.\n", i+1)
|
||||
fmt.Println("用户名: " + k.Username)
|
||||
fmt.Println("密码: " + string(pass))
|
||||
fmt.Println("上传流量: " + util.Cyan(util.Bytefmt(k.Upload)))
|
||||
fmt.Println("下载流量: " + util.Cyan(util.Bytefmt(k.Download)))
|
||||
if k.Quota < 0 {
|
||||
fmt.Println("流量限额: " + util.Cyan("无限制"))
|
||||
} else {
|
||||
fmt.Println("流量限额: " + util.Cyan(util.Bytefmt(uint64(k.Quota))))
|
||||
}
|
||||
if k.UseDays == 0 {
|
||||
fmt.Println("到期日期: " + util.Cyan("无限制"))
|
||||
} else {
|
||||
fmt.Println("到期日期: " + util.Cyan(k.ExpiryDate))
|
||||
}
|
||||
remark := url.QueryEscape(fmt.Sprintf("%s:%d", domain, port))
|
||||
fmt.Println("分享链接: " + util.Green(fmt.Sprintf("trojan://%s@%s:%d#%s", string(pass), domain, port, remark)))
|
||||
fmt.Println()
|
||||
}
|
||||
return userList
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package trojan
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"trojan/core"
|
||||
"trojan/util"
|
||||
)
|
||||
|
||||
// WebMenu web管理菜单
|
||||
func WebMenu() {
|
||||
fmt.Println()
|
||||
menu := []string{"重置web管理员密码", "修改显示的域名(非申请证书)"}
|
||||
switch util.LoopInput("请选择: ", menu, true) {
|
||||
case 1:
|
||||
ResetAdminPass()
|
||||
case 2:
|
||||
SetDomain("")
|
||||
}
|
||||
}
|
||||
|
||||
// ResetAdminPass 重置管理员密码
|
||||
func ResetAdminPass() {
|
||||
inputPass := util.Input("请输入admin用户密码: ", "")
|
||||
if inputPass == "" {
|
||||
fmt.Println("撤销更改!")
|
||||
} else {
|
||||
encryPass := sha256.Sum224([]byte(inputPass))
|
||||
err := core.SetValue("admin_pass", fmt.Sprintf("%x", encryPass))
|
||||
if err == nil {
|
||||
fmt.Println(util.Green("重置admin密码成功!"))
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetDomain 设置显示的域名
|
||||
func SetDomain(domain string) {
|
||||
if domain == "" {
|
||||
domain = util.Input("请输入要显示的域名地址: ", "")
|
||||
}
|
||||
if domain == "" {
|
||||
fmt.Println("撤销更改!")
|
||||
} else {
|
||||
core.WriteDomain(domain)
|
||||
Restart()
|
||||
fmt.Println("修改domain成功!")
|
||||
}
|
||||
}
|
||||
|
||||
// GetDomainAndPort 获取域名和端口
|
||||
func GetDomainAndPort() (string, int) {
|
||||
config := core.GetConfig()
|
||||
return config.SSl.Sni, config.LocalPort
|
||||
}
|
||||
Reference in New Issue
Block a user