Browse Source

add: client secret

Ben 1 year ago
parent
commit
3b7f4af287

+ 6 - 8
cmd/master.go

@@ -1,7 +1,7 @@
 package main
 
 import (
-	"be-vpn/internal/server"
+	"be-vpn/internal/server/master"
 	"github.com/gin-gonic/gin"
 	"log"
 )
@@ -10,13 +10,11 @@ func main() {
 	r := gin.Default()
 	r.Use(gin.Recovery())
 	r.Static("/static", "./static")
-	r.GET("/config", server.Config)
-	r.PUT("/used_duration", server.AddUsedDuration)
-	r.POST("/register", server.Register)
-	r.GET("/secret/random", server.SecretRandom)
-	r.GET("/list", server.List)
-	r.GET("/secret", server.Secret)
-	r.GET("/health", server.Health)
+	r.GET("/config", master.Config)
+	r.PUT("/used_duration", master.AddUsedDuration)
+	r.POST("/register", master.Register)
+	r.GET("/list", master.List)
+	r.GET("/health", master.Health)
 
 	if err := r.Run(":80"); err != nil {
 		log.Fatalf("err: %+v", err)

+ 14 - 48
cmd/slave.go

@@ -1,60 +1,26 @@
 package main
 
 import (
-	"be-vpn/internal/dto"
-	"bytes"
-	"encoding/json"
-	"github.com/tidwall/gjson"
-	"io"
+	"be-vpn/internal/server/slave"
+	"be-vpn/internal/task"
+	"github.com/gin-gonic/gin"
+	"github.com/robfig/cron/v3"
 	"log"
-	"net/http"
-	"os"
-	"time"
 )
 
 func main() {
-	file, err := os.Open("/root/client.ovpn")
-	if err != nil {
-		log.Fatalf("can not open file, err: %+v", err)
+	c := cron.New(cron.WithChain(cron.Recover(cron.DefaultLogger), cron.SkipIfStillRunning(cron.DefaultLogger)))
+	if _, err := c.AddFunc("@every 3s", func() {
+		task.Register()
+	}); err != nil {
+		log.Fatalf("err: %+v", err)
 	}
-	buf := bytes.Buffer{}
-	if _, err := io.Copy(&buf, file); err != nil {
-		log.Fatalf("can not read file, err: %+v", err)
-	}
-
-	resp, err := http.Get("https://ipinfo.ipidea.io")
-	if err != nil {
-		log.Fatalf("can not get resp, err: %+v", err)
-	}
-	bs, err := io.ReadAll(resp.Body)
-	if err != nil {
-		log.Fatalf("can not read resp, err: %+v", err)
-	}
-	countryCode := gjson.Get(string(bs), "country_code").String()
-	ip := gjson.Get(string(bs), "ip").String()
-	city := gjson.Get(string(bs), "city").String()
-	log.Printf("ipinfo: %s", string(bs))
 
-	request := dto.RegisterRequest{Ip: ip, CountryCode: countryCode, CountryName: city, Secret: buf.String(), City: city}
-	body, err := json.Marshal(request)
-	if err != nil {
-		log.Printf("err: %+v", err)
-	}
+	r := gin.Default()
+	r.Use(gin.Recovery())
+	r.GET("/secret", slave.Secret)
 
-	for true {
-		// send request
-		reader := bytes.NewBuffer(body)
-		resp, err := http.Post("http://v.starttransfernow.com/register", "application/json", reader)
-		if err != nil {
-			log.Printf("err: %+v", err)
-			continue
-		}
-		respBody, err := io.ReadAll(resp.Body)
-		if err != nil {
-			log.Printf("err: %+v", err)
-		}
-		log.Printf("resp: %s", string(respBody))
-		time.Sleep(3 * time.Second)
+	if err := r.Run(":80"); err != nil {
+		log.Fatalf("err: %+v", err)
 	}
-
 }

+ 2 - 0
go.mod

@@ -29,6 +29,7 @@ require (
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
+	github.com/google/uuid v1.4.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/klauspost/compress v1.15.15 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.5 // indirect
@@ -46,6 +47,7 @@ require (
 	github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect
 	github.com/prometheus/common v0.32.1 // indirect
 	github.com/prometheus/procfs v0.7.3 // indirect
+	github.com/robfig/cron/v3 v3.0.0 // indirect
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.0 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect

+ 4 - 0
go.sum

@@ -208,6 +208,8 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
 github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
 github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
+github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -340,6 +342,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
+github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=

+ 0 - 1
internal/dto/request.go

@@ -5,7 +5,6 @@ type RegisterRequest struct {
 	CountryCode string `json:"countryCode"`
 	CountryName string `json:"countryName"`
 	City        string `json:"city"`
-	Secret      string `json:"secret"`
 }
 
 type DetailRequest struct {

+ 0 - 1
internal/model/node.go

@@ -7,7 +7,6 @@ type Node struct {
 	CountryCode string
 	CountryName string
 	City        string
-	Secret      string
 
 	LastUpdateTime time.Time
 }

+ 0 - 231
internal/server/server.go

@@ -1,231 +0,0 @@
-package server
-
-import (
-	"be-vpn/internal/dto"
-	"be-vpn/internal/model"
-	"be-vpn/internal/storage"
-	"fmt"
-	"github.com/gin-gonic/gin"
-	"log"
-	"math/rand"
-	"net/http"
-	"sort"
-	"strconv"
-	"sync"
-	"time"
-)
-
-var nodes = make([]*model.Node, 0)
-var locker = sync.RWMutex{}
-var totalFreeDuration = uint64((time.Hour * 1).Milliseconds() / 1000)
-
-func Config(c *gin.Context) {
-	deviceId := c.Query("deviceId")
-	usedDuration, err := storage.GetUsedDuration(deviceId)
-	if err != nil {
-		dto.Error(c, err)
-		return
-	}
-	var node *model.Node
-	if len(healthNodes()) > 0 {
-		node = healthNodes()[0]
-	}
-	freeTrialDuration := uint64(0)
-	if usedDuration <= totalFreeDuration {
-		freeTrialDuration = totalFreeDuration - usedDuration
-	}
-
-	c.JSON(http.StatusOK, dto.ConfigResponse{
-		Response: dto.NewOkResponse(),
-		Data: dto.ConfigResult{
-			FreeTrialDuration: freeTrialDuration,
-			Timestamp:         time.Now().Unix(),
-			Node:              convert2DtoNode(node, 0),
-		},
-	})
-}
-
-func AddUsedDuration(c *gin.Context) {
-	deviceId := c.Query("deviceId")
-	usedDurationStr := c.Query("usedDuration")
-	log.Printf("deviceId: %s, usedDuration: %s", deviceId, usedDurationStr)
-
-	usedDuration, err := strconv.ParseUint(usedDurationStr, 10, 64)
-	if err != nil {
-		dto.Error(c, err)
-		return
-	}
-	if existed, err := storage.AddUsedDuration(deviceId, usedDuration); err != nil {
-		dto.Error(c, err)
-		return
-	} else {
-		freeTrialDuration := totalFreeDuration - existed
-		if freeTrialDuration > totalFreeDuration || freeTrialDuration < 0 {
-			freeTrialDuration = 0
-		}
-		c.JSON(http.StatusOK, dto.ConfigResponse{
-			Response: dto.NewOkResponse(),
-			Data: dto.ConfigResult{
-				FreeTrialDuration: freeTrialDuration,
-				Timestamp:         time.Now().Unix(),
-				Node:              convert2DtoNode(healthNodes()[0], 0),
-			},
-		})
-	}
-}
-
-func Register(c *gin.Context) {
-	locker.Lock()
-	defer locker.Unlock()
-
-	var request dto.RegisterRequest
-	if err := c.ShouldBindJSON(&request); err != nil {
-		dto.BadRequest(c, err)
-		return
-	}
-
-	for _, node := range nodes {
-		if node.Ip == request.Ip {
-			node.Ip = request.Ip
-			node.Secret = request.Secret
-			node.CountryCode = request.CountryCode
-			node.CountryName = request.CountryName
-			node.City = request.City
-			node.LastUpdateTime = time.Now()
-			c.JSON(http.StatusOK, dto.RegisterResponse{
-				Response: dto.NewOkResponse(),
-				Data: dto.RegisterResult{
-					Success: true,
-				},
-			})
-			return
-		}
-	}
-	node := &model.Node{
-		Ip:             request.Ip,
-		Secret:         request.Secret,
-		LastUpdateTime: time.Now(),
-	}
-	nodes = append(nodes, node)
-	log.Printf("update nodes: %+v", nodes)
-}
-
-func List(c *gin.Context) {
-	locker.RLock()
-	defer locker.RUnlock()
-
-	nodes := healthNodes()
-	sort.SliceStable(nodes, func(i, j int) bool {
-		return nodes[i].CountryCode > nodes[j].CountryCode
-	})
-
-	countryLabelSeqs := make(map[string]int)
-	dtoNodes := make([]*dto.Node, 0)
-	for _, node := range nodes {
-		seq, ok := countryLabelSeqs[node.CountryCode]
-		if !ok {
-			countryLabelSeqs[node.CountryCode] = 0
-		} else {
-			countryLabelSeqs[node.CountryCode] = seq + 1
-		}
-		dtoNodes = append(dtoNodes, convert2DtoNode(node, countryLabelSeqs[node.CountryCode]))
-	}
-
-	c.JSON(http.StatusOK, dto.ListResponse{
-		Response: dto.NewOkResponse(),
-		Data:     dtoNodes,
-	})
-}
-
-func SecretRandom(c *gin.Context) {
-	locker.RLock()
-	defer locker.RUnlock()
-
-	random := rand.Intn(len(nodes))
-
-	for i, node := range nodes {
-		if i == random {
-			c.Header("Content-Disposition", "attachment; filename=client.ovpn")
-			c.Data(http.StatusOK, "plain/text", []byte(node.Secret))
-			return
-		}
-	}
-	c.JSON(http.StatusNotFound, gin.H{
-		"message": "not found",
-	})
-}
-
-func Secret(c *gin.Context) {
-	locker.RLock()
-	defer locker.RUnlock()
-
-	var request dto.DetailRequest
-	if err := c.ShouldBindQuery(&request); err != nil {
-		dto.BadRequest(c, err)
-		return
-	}
-
-	for _, node := range nodes {
-		if node.Ip == request.Ip {
-			//secret, err := util.AesEncrypt([]byte(node.Secret))
-			//if err != nil {
-			//	dto.Error(c, err)
-			//	return
-			//}
-			c.Header("Content-Disposition", "attachment; filename=client.ovpn")
-			c.Data(http.StatusOK, "plain/text", []byte(node.Secret))
-			return
-		}
-	}
-	c.JSON(http.StatusNotFound, gin.H{
-		"message": "not found ip",
-	})
-}
-
-func Health(c *gin.Context) {
-	c.JSON(http.StatusOK, gin.H{"status": "up"})
-}
-
-func healthNodes() []*model.Node {
-	healthNodes := make([]*model.Node, 0)
-	for _, node := range nodes {
-		if node.LastUpdateTime.Add(10 * time.Second).After(time.Now()) {
-			healthNodes = append(healthNodes, node)
-		}
-	}
-	return healthNodes
-}
-
-func convert2DtoNode(node *model.Node, seq int) *dto.Node {
-	if node == nil {
-		return nil
-	}
-	icons := map[string]string{
-		"BR": "http://v.starttransfernow.com/static/BR.jpg",
-		"DE": "http://v.starttransfernow.com/static/DE.jpg",
-		"HK": "http://v.starttransfernow.com/static/HK.jpg",
-		"JP": "http://v.starttransfernow.com/static/JP.jpg",
-		"US": "http://v.starttransfernow.com/static/US.jpg",
-		"UK": "http://v.starttransfernow.com/static/UK.jpg",
-		"GB": "http://v.starttransfernow.com/static/UK.jpg",
-	}
-	countryLabels := map[string]string{
-		"BR": "Brazil",
-		"DE": "Germany",
-		"HK": "Hong Kong",
-		"JP": "Japan",
-		"US": "United States",
-		"UK": "United Kingdom",
-		"GB": "United Kingdom",
-	}
-
-	return &dto.Node{
-		Ip:           node.Ip,
-		CountryCode:  node.CountryCode,
-		CountryName:  node.CountryName,
-		City:         node.City,
-		CountryLabel: fmt.Sprintf("%s - %d", countryLabels[node.CountryCode], seq+1),
-		Icon:         icons[node.CountryCode],
-		SecretUrl:    fmt.Sprintf("http://v.starttransfernow.com/secret?ip=%s", node.Ip),
-	}
-}

+ 49 - 0
internal/task/register.go

@@ -0,0 +1,49 @@
+package task
+
+import (
+	"be-vpn/internal/dto"
+	"bytes"
+	"encoding/json"
+	"github.com/tidwall/gjson"
+	"io"
+	"log"
+	"net/http"
+)
+
+func Register() {
+	resp, err := http.Get("https://ipinfo.ipidea.io")
+	if err != nil {
+		log.Fatalf("can not get resp, err: %+v", err)
+	}
+	bs, err := io.ReadAll(resp.Body)
+	if err != nil {
+		log.Printf("can not read resp, err: %+v", err)
+		return
+	}
+	countryCode := gjson.Get(string(bs), "country_code").String()
+	ip := gjson.Get(string(bs), "ip").String()
+	city := gjson.Get(string(bs), "city").String()
+	log.Printf("ipinfo: %s", string(bs))
+
+	request := dto.RegisterRequest{Ip: ip, CountryCode: countryCode, CountryName: city, City: city}
+	body, err := json.Marshal(request)
+	if err != nil {
+		log.Printf("err: %+v", err)
+		return
+	}
+
+	// send request
+	reader := bytes.NewBuffer(body)
+	resp, err = http.Post("http://v.starttransfernow.com/register", "application/json", reader)
+	if err != nil {
+		log.Printf("err: %+v", err)
+		return
+	}
+	respBody, err := io.ReadAll(resp.Body)
+	if err != nil {
+		log.Printf("err: %+v", err)
+		return
+	}
+	log.Printf("resp: %s", string(respBody))
+
+}

+ 0 - 57
internal/util/rsa.go

@@ -1,57 +0,0 @@
-package util
-
-import (
-	"bytes"
-	"crypto/aes"
-	"crypto/cipher"
-	"errors"
-)
-
-var key = []byte("e2joejiad0wu38912!E2921d!@@1e23u")
-
-// pkcs7Padding 填充
-func pkcs7Padding(data []byte, blockSize int) []byte {
-	padding := blockSize - len(data)%blockSize
-	padText := bytes.Repeat([]byte{byte(padding)}, padding)
-	return append(data, padText...)
-}
-
-// pkcs7UnPadding 填充的反向操作
-func pkcs7UnPadding(data []byte) ([]byte, error) {
-	length := len(data)
-	if length == 0 {
-		return nil, errors.New("加密字符串错误!")
-	}
-	unPadding := int(data[length-1])
-	return data[:(length - unPadding)], nil
-}
-
-// AesEncrypt 加密
-func AesEncrypt(data []byte) ([]byte, error) {
-	block, err := aes.NewCipher(key)
-	if err != nil {
-		return nil, err
-	}
-	blockSize := block.BlockSize()
-	encryptBytes := pkcs7Padding(data, blockSize)
-	crypted := make([]byte, len(encryptBytes))
-	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
-	blockMode.CryptBlocks(crypted, encryptBytes)
-	return crypted, nil
-}
-
-func AesDecrypt(data []byte) ([]byte, error) {
-	block, err := aes.NewCipher(key)
-	if err != nil {
-		return nil, err
-	}
-	blockSize := block.BlockSize()
-	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
-	crypted := make([]byte, len(data))
-	blockMode.CryptBlocks(crypted, data)
-	crypted, err = pkcs7UnPadding(crypted)
-	if err != nil {
-		return nil, err
-	}
-	return crypted, nil
-}

+ 34 - 0
scripts/ec2_luanch_template.sh

@@ -0,0 +1,34 @@
+#!/bin/bash
+yum update -y
+
+ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa <<<y >/dev/null 2>&1
+
+token=b0929fa414cefbb6266b8760fd0c8107421c33c0
+key=$(cat ~/.ssh/id_rsa.pub)
+echo $key
+now=$(date +%Y-%m-%dT%H:%M:%S.%N)
+echo $now
+
+curl -H "Authorization: token $token" -XPOST http://hubgit.cn/api/v1/user/keys -H 'content-type: application/json' -d"{\"title\":\"slave$now\", \"key\": \"$key\"}"
+
+rm -rf /var/run/yum.pid
+yum install git -y
+
+# clone project
+ssh-keygen -F hubgit.cn || ssh-keyscan hubgit.cn >>~/.ssh/known_hosts
+git clone root@hubgit.cn:ben/be-vpn.git
+cd be-vpn
+
+# install openvpn
+chmod +x ./scripts/openvpn-install.sh
+export AUTO_INSTALL=y && ./scripts/openvpn-install.sh
+
+# install golang
+rm -rf /var/run/yum.pid
+yum install golang -y
+export HOME=/root
+export GOPATH=$HOME/go
+export PATH=$PATH:$GOPATH/bin
+go env -w GOMODCACHE=/go/pkg
+go build ./cmd/slave.go
+nohup ./slave &

+ 0 - 0
run_master.sh → scripts/master.sh


+ 0 - 0
scripts/openvpn-install.sh