Browse Source

feat: init

Ben 1 year ago
commit
da23e53d54
13 changed files with 516 additions and 0 deletions
  1. 8 0
      .idea/.gitignore
  2. 19 0
      cmd/master/master.go
  3. 113 0
      cmd/master/server.go
  4. 55 0
      cmd/slave/slave.go
  5. 41 0
      go.mod
  6. 108 0
      go.sum
  7. 10 0
      internal/dto/request.go
  8. 63 0
      internal/dto/response.go
  9. 11 0
      internal/model/node.go
  10. 63 0
      internal/util/rsa.go
  11. 4 0
      proxy.iml
  12. 15 0
      rsa_private.pem
  13. 6 0
      rsa_public.pem

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 19 - 0
cmd/master/master.go

@@ -0,0 +1,19 @@
+package main
+
+import (
+	"github.com/gin-gonic/gin"
+	"log"
+)
+
+func main() {
+	r := gin.Default()
+	r.Use(gin.Recovery())
+	r.POST("/register", register)
+	r.GET("/list", list)
+	r.GET("/detail", detail)
+	r.GET("/health", health)
+
+	if err := r.Run(":8080"); err != nil {
+		log.Fatalf("err: %+v", err)
+	}
+}

+ 113 - 0
cmd/master/server.go

@@ -0,0 +1,113 @@
+package main
+
+import (
+	"github.com/gin-gonic/gin"
+	"log"
+	"net/http"
+	"proxy/internal/dto"
+	"proxy/internal/model"
+	"proxy/internal/util"
+	"sync"
+	"time"
+)
+
+var nodes = make([]*model.Node, 0)
+var locker = sync.RWMutex{}
+
+func register(c *gin.Context) {
+	locker.Lock()
+	defer locker.Unlock()
+
+	ip := c.RemoteIP()
+
+	var request dto.RegisterRequest
+	if err := c.ShouldBindJSON(&request); err != nil {
+		dto.BadRequest(c, err)
+		return
+	}
+
+	for _, node := range nodes {
+		if node.Ip == ip {
+			node.Ip = ip
+			node.Secret = request.Secret
+			node.CountryCode = request.CountryCode
+			node.LastUpdateTime = time.Now()
+			c.JSON(http.StatusOK, dto.RegisterResponse{
+				Response: dto.NewOkResponse(),
+				Data: dto.RegisterResult{
+					Success: true,
+				},
+			})
+			return
+		}
+	}
+	node := &model.Node{
+		Ip:             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()
+
+	dtoNodes := make(map[string][]dto.Node)
+	for _, node := range nodes {
+		if _, ok := dtoNodes[node.CountryCode]; !ok {
+			dtoNodes[node.CountryCode] = make([]dto.Node, 0)
+		}
+		if node.LastUpdateTime.Add(10 * time.Second).After(time.Now()) {
+			dtoNodes[node.CountryCode] = append(dtoNodes[node.CountryCode], dto.Node{
+				Ip: node.Ip,
+			})
+		}
+	}
+
+	listResult := make([]dto.ListResult, len(dtoNodes))
+	i := 0
+	for countryCode, itemNodes := range dtoNodes {
+		listResult[i] = dto.ListResult{
+			CountryCode: countryCode,
+			Nodes:       itemNodes,
+		}
+		i++
+	}
+
+	c.JSON(http.StatusOK, dto.ListResponse{
+		Response: dto.NewOkResponse(),
+		Data:     listResult,
+	})
+}
+
+func detail(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.RsaEncrypt([]byte(node.Secret))
+			if err != nil {
+				dto.Error(c, err)
+				return
+			}
+			c.Data(http.StatusOK, "application/octet-stream", 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"})
+}

+ 55 - 0
cmd/slave/slave.go

@@ -0,0 +1,55 @@
+package main
+
+import (
+	"bytes"
+	"encoding/json"
+	"github.com/robfig/cron/v3"
+	"github.com/tidwall/gjson"
+	"io"
+	"log"
+	"net/http"
+	"os"
+	"proxy/internal/dto"
+)
+
+func main() {
+	file, err := os.Open("/root/client.ovpn")
+	if err != nil {
+		log.Fatalf("can not open file, 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()
+	log.Printf("get country code: %s", countryCode)
+
+	request := dto.RegisterRequest{CountryCode: countryCode, Secret: buf.String()}
+	body, err := json.Marshal(request)
+
+	c := cron.New(cron.WithChain(cron.SkipIfStillRunning(cron.DefaultLogger)))
+	if _, err := c.AddFunc("* * * * *", func() {
+		// send request
+		reader := bytes.NewBuffer(body)
+		resp, err := http.Post("https://localhost:8080/register", "application/json", reader)
+		if err != nil {
+			log.Printf("err: %+v", err)
+		}
+		respBody, err := io.ReadAll(resp.Body)
+		if err != nil {
+			log.Printf("err: %+v", err)
+		}
+		log.Printf("resp: %s", string(respBody))
+	}); err != nil {
+		log.Fatalf("err: %+v", err)
+	}
+}

+ 41 - 0
go.mod

@@ -0,0 +1,41 @@
+module proxy
+
+go 1.19
+
+require github.com/gin-gonic/gin v1.9.1
+
+require (
+	github.com/bytedance/sonic v1.10.0-rc2 // indirect
+	github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
+	github.com/chenzhuoyu/iasm v0.9.0 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.2 // indirect
+	github.com/gin-contrib/sse v0.1.0 // indirect
+	github.com/go-playground/locales v0.14.1 // indirect
+	github.com/go-playground/universal-translator v0.18.1 // indirect
+	github.com/go-playground/validator/v10 v10.14.1 // indirect
+	github.com/goccy/go-json v0.10.2 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.5 // indirect
+	github.com/kr/text v0.2.0 // indirect
+	github.com/leodido/go-urn v1.2.4 // indirect
+	github.com/mattn/go-isatty v0.0.19 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
+	github.com/pelletier/go-toml/v2 v2.0.9 // indirect
+	github.com/robfig/cron/v3 v3.0.1 // indirect
+	github.com/tidwall/gjson v1.14.4 // 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
+	github.com/ugorji/go/codec v1.2.11 // indirect
+	golang.org/x/arch v0.4.0 // indirect
+	golang.org/x/crypto v0.11.0 // indirect
+	golang.org/x/net v0.12.0 // indirect
+	golang.org/x/sys v0.10.0 // indirect
+	golang.org/x/text v0.11.0 // indirect
+	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
+	google.golang.org/protobuf v1.31.0 // indirect
+	gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)

+ 108 - 0
go.sum

@@ -0,0 +1,108 @@
+github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
+github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
+github.com/bytedance/sonic v1.10.0-rc2 h1:oDfRZ+4m6AYCOC0GFeOCeYqvBmucy1isvouS2K0cPzo=
+github.com/bytedance/sonic v1.10.0-rc2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
+github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
+github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
+github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
+github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
+github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
+github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
+github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
+github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
+github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
+github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
+github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
+github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
+github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
+github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
+github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
+github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
+github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc=
+golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
+golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
+golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
+golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
+golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
+golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
+gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

+ 10 - 0
internal/dto/request.go

@@ -0,0 +1,10 @@
+package dto
+
+type RegisterRequest struct {
+	CountryCode string `json:"countryCode"`
+	Secret      string `json:"secret"`
+}
+
+type DetailRequest struct {
+	Ip string `form:"ip"`
+}

+ 63 - 0
internal/dto/response.go

@@ -0,0 +1,63 @@
+package dto
+
+import (
+	"github.com/gin-gonic/gin"
+	"log"
+	"net/http"
+	"runtime/debug"
+)
+
+func BadRequest(c *gin.Context, err error) {
+	log.Printf("err: %+v", err)
+	debug.PrintStack()
+	c.JSON(http.StatusBadRequest, Response{
+		Status:  0,
+		Message: err.Error(),
+	})
+}
+
+func Error(c *gin.Context, err error) {
+	log.Printf("err: %+v", err)
+	debug.PrintStack()
+	c.JSON(http.StatusInternalServerError, Response{
+		Status:  0,
+		Message: err.Error(),
+	})
+}
+
+func NewOkResponse() Response {
+	return Response{Status: 1, Message: "ok"}
+}
+
+type Response struct {
+	Status  int    `json:"status"`
+	Message string `json:"message"`
+}
+
+type RegisterResponse struct {
+	Response
+	Data RegisterResult `json:"data"`
+}
+
+type RegisterResult struct {
+	Success bool `json:"success"`
+}
+
+type ListResponse struct {
+	Response
+	Data []ListResult `json:"data"`
+}
+
+type ListResult struct {
+	CountryCode string `json:"countryCode"`
+	Nodes       []Node `json:"nodes"`
+}
+
+type Node struct {
+	Ip string `json:"ip"`
+}
+
+type DetailResponse struct {
+	Response
+	Data Node `json:"data"`
+}

+ 11 - 0
internal/model/node.go

@@ -0,0 +1,11 @@
+package model
+
+import "time"
+
+type Node struct {
+	Ip          string
+	CountryCode string
+	Secret      string
+
+	LastUpdateTime time.Time
+}

+ 63 - 0
internal/util/rsa.go

@@ -0,0 +1,63 @@
+package util
+
+import (
+	"bytes"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+	"io"
+	"log"
+	"os"
+)
+
+var publicKey []byte
+var privateKey []byte
+
+func init() {
+	publicFile, err := os.Open("rsa_public.pem")
+	if err != nil {
+		log.Fatalf("can not open publicFile, err: %+v", err)
+	}
+	publicBuf := bytes.Buffer{}
+	if _, err := io.Copy(&publicBuf, publicFile); err != nil {
+		log.Fatalf("can not read publicFile, err: %+v", err)
+	}
+	publicKey = publicBuf.Bytes()
+
+	privateFile, err := os.Open("rsa_private.pem")
+	if err != nil {
+		log.Fatalf("can not open privateFile, err: %+v", err)
+	}
+	privateBuf := bytes.Buffer{}
+	if _, err := io.Copy(&privateBuf, privateFile); err != nil {
+		log.Fatalf("can not read privateFile, err: %+v", err)
+	}
+	privateKey = privateBuf.Bytes()
+}
+
+func RsaEncrypt(origData []byte) ([]byte, error) {
+	block, _ := pem.Decode(publicKey)
+	if block == nil {
+		return nil, errors.New("public key error")
+	}
+	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+	pub := pubInterface.(*rsa.PublicKey)
+	return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
+}
+
+func RsaDecrypt(ciphertext []byte) ([]byte, error) {
+	block, _ := pem.Decode(privateKey)
+	if block == nil {
+		return nil, errors.New("private key error!")
+	}
+	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+	return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
+}

+ 4 - 0
proxy.iml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="Go" enabled="true" />
+</module>

+ 15 - 0
rsa_private.pem

@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC5k28HzW0D+Yj2fgf58Wim+0xFX2IisOdVieWyXu5zJQhHxd5G
+6LZus9Wf0WZeWrnvnU3krIHbDJVGReJCXROpHwZFecvdtTw1dbfL7EMeMDsLG+Ba
+RuX/VYMHjsbyJnb3+4aLU7doiafGLALgEundfib5z1UUEYs1LpH4eEnUQQIDAQAB
+AoGAVz1JD/jxi9HOIlqjM0var80pUN+DSd2yEtNNySm5nSXGm78YPGt//9DI12Xg
+YvDxwgRILv0t2qUys6N8t0f8SlK4DaFusNZjHXC2AnddBdn1Gz+WvBhwdk4HNz4T
+fpRZVGAO06HIe8XsZMy1odmD7QaKYybLBW6MmFO+6u3r5cECQQDn+mg3Z8W4Ooif
+5ixfoIkxpWDNmKCSb8g768JnbjeA9DBrNqzs88Ac2pOi4xmVMOi2fLkaQZw4Pt23
+znX5B6H5AkEAzMruzfE9qW6xrlRZ8qkR256e9TaeiD5arReyIJGEdpB1eStE39zM
+D17vkglPjzcgtyavvhLTlAxxyOpTM77WiQJAVYD6wNFDE3CfwzA30td9OgtW7vD+
+3nrNNyji8vSxCJr47cutWXlOqlP2bud+Gnt4iyrVn1PnnOOvHXzABxZFIQJACQ8U
+/zEjrCIEZBTBIdXOv2tF1s0CuD4h3rREoeIt/NypBaIfWtO2hxuI92nIBirHHLLu
+ZTcJ+uuOAPg0k/5mGQJBANLGUCTcaaR4+KIGFHG4pk/+JVLk0kJ4kk0H58esrVfD
+OErkUQPbKLTtBvPbwcm3St/mm8zXiEqyp/jFjznHfSo=
+-----END RSA PRIVATE KEY-----

+ 6 - 0
rsa_public.pem

@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5k28HzW0D+Yj2fgf58Wim+0xF
+X2IisOdVieWyXu5zJQhHxd5G6LZus9Wf0WZeWrnvnU3krIHbDJVGReJCXROpHwZF
+ecvdtTw1dbfL7EMeMDsLG+BaRuX/VYMHjsbyJnb3+4aLU7doiafGLALgEundfib5
+z1UUEYs1LpH4eEnUQQIDAQAB
+-----END PUBLIC KEY-----