0x4a52466c696e74 2 years ago
commit
009ee939b8
19 changed files with 1205 additions and 0 deletions
  1. 94 0
      api.go
  2. 107 0
      application.go
  3. 27 0
      browser.go
  4. 4 0
      build.sh
  5. 106 0
      client.go
  6. 54 0
      clients.go
  7. 3 0
      config.ini
  8. BIN
      curve-app
  9. BIN
      curve-app.exe
  10. 79 0
      curve.go
  11. 27 0
      go.mod
  12. 131 0
      go.sum
  13. 16 0
      html/index.html
  14. 48 0
      html/java/main.js
  15. 133 0
      html/java/socket.js
  16. 47 0
      main.go
  17. 53 0
      message.go
  18. 245 0
      method.go
  19. 31 0
      tools.go

+ 94 - 0
api.go

@@ -0,0 +1,94 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"math/big"
+	"os"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"git.ali33.ru/fcg-xvii/go-tools/json"
+)
+
+var (
+	idContext    int32 = 0
+	contextStore       = new(sync.Map)
+)
+
+func getContextID() int {
+	return int(atomic.AddInt32(&idContext, 1))
+}
+
+func messageIncoming(mes *Message) {
+	mData := mes.Data()
+	if mData.String("type", "") == "event" {
+		// event
+	} else {
+		command := mData.String("command", "")
+		switch command {
+		case "method":
+			log.Println("METHOD")
+			randomNum, check := checkBigInt(mes, "random_num")
+			if !check {
+				randomNum = big.NewInt(1000000)
+			}
+			message := mData.String(
+				"message",
+				"Демонстрация работы алгоритмов шифрования Диффи-Хеллмана и Эль-Гамаля на эллиптических кривых и атаки на них.",
+			)
+			deadline := time.Now().Add(time.Duration(mData.Int("deadline_sec", 600)) * time.Second)
+			contextID := getContextID()
+			mes.SendResponse(json.Map{
+				"context_id": contextID,
+				"random_num": randomNum,
+				"deadline":   deadline.Unix(),
+				"message":    message,
+			})
+			ctx, cancel := context.WithDeadline(mes.Client().Context(), deadline)
+			contextStore.Store(contextID, cancel)
+			go func() {
+				cl := mes.Client()
+				for e := range MethodCurve(randomNum, message, ctx, contextID) {
+					cl.SendSingle(e.Map())
+				}
+				log.Println("CONTEXT_STOPPED", contextID)
+			}()
+		case "context_stop":
+			contextID := mData.Int32("context_id", -1)
+			if contextID == -1 {
+				mes.SendResponse(json.Map{
+					"error": true,
+					"text":  "Ожидается context_id",
+				})
+				return
+			}
+			cancel, check := contextStore.LoadAndDelete(contextID)
+			if !check {
+				mes.SendResponse(json.Map{
+					"error": true,
+					"text":  fmt.Sprintf("контекст [ %s ] не найден", contextID),
+				})
+				return
+			}
+			cancel.(context.CancelFunc)()
+			mes.SendResponse(json.Map{
+				"context_id": contextID,
+				"text":       "Контекст остановлен",
+			})
+		case "exit":
+			os.Exit(0)
+		default:
+			if mes.IsResponsable() {
+				mes.SendResponse(json.Map{
+					"error": true,
+					"text":  fmt.Sprintf("команда [ %s ] не найдена", command),
+				})
+			}
+		}
+	}
+
+	mData.LogPretty()
+}

+ 107 - 0
application.go

@@ -0,0 +1,107 @@
+package main
+
+import (
+	"log"
+	"os"
+	"time"
+
+	"git.ali33.ru/fcg-xvii/net/v3/http/engine"
+	"github.com/gorilla/websocket"
+)
+
+func NewWSEngine(base engine.Engine, urlPath string) *WSEngine {
+	res := &WSEngine{
+		Engine:   base,
+		urlPath:  urlPath,
+		clients:  NewWSClients(),
+		listener: make(chan *WSClient),
+	}
+	return res
+}
+
+type WSEngine struct {
+	engine.Engine
+	urlPath  string
+	clients  *WSClients
+	upgrader websocket.Upgrader
+	listener chan *WSClient
+}
+
+func (s *WSEngine) Listener() <-chan *WSClient {
+	return s.listener
+}
+
+func (s *WSEngine) Exec(req *engine.Request, resp *engine.Response) {
+	if req.URL.Path == s.urlPath {
+		if conn, err := s.upgrader.Upgrade(resp.ResponseWriter(), req.Request, nil); err == nil {
+			cl := s.clients.clientConnected(conn)
+			select {
+			case s.listener <- cl:
+			default:
+			}
+		}
+		return
+	}
+	s.Engine.Exec(req, resp)
+}
+
+/////////////////////////////
+
+func NewApplication(addr string) engine.Engine {
+	params := map[string]any{
+		"addr": addr,
+	}
+	app := engine.NewEngineBase(params, nil, "html")
+	wsApp := NewWSEngine(app, "/api")
+
+	go func() {
+		for cl := range wsApp.Listener() {
+			//log.Println("CL.....", cl)
+			go func(c *WSClient) {
+				//log.Println("CL-READ")
+				for mes := range c.Read() {
+					log.Println("------>", mes)
+					messageIncoming(mes)
+				}
+				//log.Println("CL-CLOSE")
+				t := time.NewTimer(time.Second * time.Duration(downTime))
+				<-t.C
+				if c.clients.Size() == 0 {
+					os.Exit(0)
+				}
+			}(cl)
+		}
+	}()
+
+	return wsApp
+}
+
+/*
+type WebsocketAppChecker struct {
+	clients *Clients
+}
+
+func (s *WebsocketAppChecker) RequestCheck(r *engine.Request) bool {
+	log.Println("CHECK", r.URL.Path)
+	return r.URL.Path == "/api"
+}
+
+func NewWebsocketApplication(base engine.Engine) engine.Engine {
+	app := &WebsocketAppChecker{
+
+	}
+	websocketApp := engine.NewWebsocketApplication(app, engine.DefaultUpgrader())
+	go func() {
+		for conn := range websocketApp.Listener() {
+			.clientConnected(conn)
+		}
+	}()
+
+	websocketEngine := engine.NewEngineWebsocket(
+		base,
+		websocketApp,
+	)
+	return websocketEngine
+	//dapp := engine.NewEngineDomainBase(wapp, 302, "anapa-2.lan")
+}
+*/

+ 27 - 0
browser.go

@@ -0,0 +1,27 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"os/exec"
+	"runtime"
+)
+
+func openURI(url string) {
+	var err error
+
+	switch runtime.GOOS {
+	case "linux":
+		err = exec.Command("xdg-open", url).Start()
+	case "windows":
+		err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
+	case "darwin":
+		err = exec.Command("open", url).Start()
+	default:
+		err = fmt.Errorf("unsupported platform")
+	}
+	if err != nil {
+		log.Fatal(err)
+	}
+
+}

+ 4 - 0
build.sh

@@ -0,0 +1,4 @@
+# my OS
+go build
+# windows
+GOOS=windows GOARCH=amd64 go build

+ 106 - 0
client.go

@@ -0,0 +1,106 @@
+package main
+
+import (
+	"log"
+	"time"
+
+	"git.ali33.ru/fcg-xvii/go-tools/json"
+	"github.com/gorilla/websocket"
+	"golang.org/x/net/context"
+)
+
+type WSClient struct {
+	clients *WSClients
+	conn    *websocket.Conn
+	ctx     context.Context
+	cancel  context.CancelFunc
+	//callClose    func(*WSClient)
+	//callIncoming func(*WSClient, json.Map)
+}
+
+func (s *WSClient) SendData(data json.Map) error {
+	w, err := s.conn.NextWriter(websocket.TextMessage)
+	if err != nil {
+		return err
+	}
+	_, err = w.Write(data.JSON())
+	w.Close()
+	return err
+}
+
+func (s *WSClient) SendSingle(data json.Map) error {
+	jm := json.Map{
+		"data": data,
+	}
+	return s.SendData(jm)
+}
+
+func (s *WSClient) SendMessage(data json.Map, deadline time.Duration) (<-chan json.Map, error) {
+	dl := time.Now().Add(deadline)
+	id := s.clients.nextID()
+	jm := json.Map{
+		"id":   id,
+		"data": data,
+	}
+	if err := s.SendData(jm); err != nil {
+		return nil, err
+	}
+	ctx, _ := context.WithDeadline(context.Background(), dl)
+	ch := make(chan json.Map)
+	rch := make(chan json.Map)
+	s.clients.rStore.Store(id, ch)
+	go func() {
+		select {
+		case <-ctx.Done():
+			s.clients.rStore.Delete(id)
+			close(rch)
+		case rData := <-ch:
+			select {
+			case rch <- rData:
+			default:
+			}
+		}
+	}()
+	return rch, nil
+}
+
+func (s *WSClient) Context() context.Context {
+	return s.ctx
+}
+
+func (s *WSClient) Read() <-chan *Message {
+	ch := make(chan *Message, 10)
+	go func() {
+		defer func() {
+			s.cancel()
+			close(ch)
+		}()
+		for {
+			t, src, err := s.conn.ReadMessage()
+			log.Println(t, string(src), err)
+			if err != nil {
+				s.clients.clientDisconnected(s)
+				return
+			}
+			var jm json.Map
+			if err = json.Unmarshal(src, &jm); err == nil {
+				if jm.Bool("is_response", false) {
+					//log.Println("AAAAAAAAAAAAAAAAAAA")
+					if rch, check := s.clients.rStore.LoadAndDelete(jm.Int("id", -1)); check {
+						rch.(chan json.Map) <- jm.Map("data", json.Map{})
+					}
+				} else {
+					//log.Println("UUUUUUUUUUUUUUUU")
+					mes := MessageFromMap(jm, s)
+					select {
+					case ch <- mes:
+					default:
+					}
+				}
+			}
+		}
+	}()
+	return ch
+}
+
+/////////////////////////

+ 54 - 0
clients.go

@@ -0,0 +1,54 @@
+package main
+
+import (
+	"context"
+	"log"
+	"sync"
+	"sync/atomic"
+
+	"git.ali33.ru/fcg-xvii/go-tools/containers/concurrent"
+	"git.ali33.ru/fcg-xvii/go-tools/json"
+	"github.com/gorilla/websocket"
+)
+
+func NewWSClients() *WSClients {
+	return &WSClients{
+		List:   concurrent.NewList(),
+		rStore: new(sync.Map),
+	}
+}
+
+type WSClients struct {
+	*concurrent.List
+	rStore  *sync.Map
+	counter uint32
+}
+
+func (s *WSClients) Broadcast(mes json.Map) {
+	for e := s.First(); e != nil; e = e.Next() {
+		e.Val().(*WSClient).SendSingle(mes)
+	}
+}
+
+func (s *WSClients) clientConnected(conn *websocket.Conn) *WSClient {
+	cctx, cancel := context.WithCancel(context.Background())
+	cl := &WSClient{
+		conn:    conn,
+		clients: s,
+		ctx:     cctx,
+		cancel:  cancel,
+	}
+	s.PushBack(cl)
+	return cl
+}
+
+func (s *WSClients) clientDisconnected(cl *WSClient) {
+	log.Println("DISCONNECTED")
+	if e := s.Search(cl); e != nil {
+		s.Remove(e)
+	}
+}
+
+func (s *WSClients) nextID() int64 {
+	return int64(atomic.AddUint32(&s.counter, 1))
+}

+ 3 - 0
config.ini

@@ -0,0 +1,3 @@
+listen     = 127.0.0.1:34775
+debug_mode = false
+downtime   = 5

BIN
curve-app


BIN
curve-app.exe


+ 79 - 0
curve.go

@@ -0,0 +1,79 @@
+package main
+
+import (
+	"context"
+	"sync/atomic"
+	"time"
+
+	"git.ali33.ru/fcg-xvii/curve/v2"
+	"git.ali33.ru/fcg-xvii/curve/v2/tools"
+	"git.ali33.ru/fcg-xvii/go-tools/containers/concurrent"
+	"git.ali33.ru/fcg-xvii/go-tools/json"
+)
+
+var (
+	curveStore = &CurveStore{
+		List: concurrent.NewList(),
+		cid:  int32(0),
+	}
+)
+
+type Curve struct {
+	*tools.Curve
+	id int32
+}
+
+func (s *Curve) Map() json.Map {
+	res := s.Curve.Map()
+	res["id"] = s.id
+	return res
+}
+
+func (s *Curve) MarshalJSON() ([]byte, error) {
+	return s.Map().JSON(), nil
+}
+
+type CurveStore struct {
+	*concurrent.List
+	cid int32
+}
+
+func (s *CurveStore) APICurveInit(mes *Message) {
+	mData := mes.Data()
+	a, check := checkBigInt(mes, "a")
+	if !check {
+		return
+	}
+	b, check := checkBigInt(mes, "b")
+	if !check {
+		return
+	}
+	p, check := checkBigInt(mes, "p")
+	if !check {
+		return
+	}
+	ctx, _ := context.WithDeadline(
+		context.Background(),
+		time.Now().Add(time.Second*time.Duration(mData.Int("deadline_seconds", 30))),
+	)
+	c, err := curve.NewCurve(a, b, p, ctx)
+	if err != nil {
+		mes.SendResponse(messageError(err.Error()))
+		return
+	}
+	cur := &Curve{
+		Curve: c,
+		id:    atomic.AddInt32(&s.cid, 1),
+	}
+	s.PushBack(cur)
+	mes.SendResponse(json.Map{
+		"curve": cur.Map(),
+	})
+}
+
+func (s *CurveStore) APICurves(mes *Message) {
+	curves := s.List.Slice()
+	mes.SendResponse(json.Map{
+		"curves": curves,
+	})
+}

+ 27 - 0
go.mod

@@ -0,0 +1,27 @@
+module curve-app
+
+go 1.18
+
+require (
+	git.ali33.ru/fcg-xvii/curve/v2 v2.0.8
+	git.ali33.ru/fcg-xvii/go-tools v0.0.0-20221003202615-4f03edf5cf03
+	git.ali33.ru/fcg-xvii/net/v3 v3.2.1
+	github.com/gorilla/websocket v1.5.0
+	golang.org/x/net v0.1.0
+)
+
+require (
+	git.ali33.ru/fcg-xvii/metla v0.0.0-20220925104102-c0394c741ec0 // indirect
+	git.ali33.ru/fcg-xvii/mjs v0.0.0-20221008153018-6dc4c41d564e // indirect
+	github.com/dlclark/regexp2 v1.7.0 // indirect
+	github.com/dop251/goja v0.0.0-20221024130056-0ad46a434ac5 // indirect
+	github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
+	github.com/jackc/pgpassfile v1.0.0 // indirect
+	github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
+	github.com/jackc/pgx/v5 v5.0.3 // indirect
+	github.com/sirupsen/logrus v1.9.0 // indirect
+	github.com/xlab/closer v1.1.0 // indirect
+	golang.org/x/crypto v0.1.0 // indirect
+	golang.org/x/sys v0.1.0 // indirect
+	golang.org/x/text v0.4.0 // indirect
+)

+ 131 - 0
go.sum

@@ -0,0 +1,131 @@
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.1 h1:oEICvD/SJqguJ4NaMHCPycSH+ZBXp6ftpfFZH7VVqoo=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.1/go.mod h1:eGQ1B63EQk4oPgIH6++g9Yv9VTrGEsVZKQN3rDos0YE=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.2 h1:aBQY/kvaIfqblnptnyksv05ERKrgc2fHedYlYFl7pUE=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.2/go.mod h1:eGQ1B63EQk4oPgIH6++g9Yv9VTrGEsVZKQN3rDos0YE=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.3 h1:CMEN/YnTF92HdYZk4yBdvA4m5ulr37oMiUHjiaCSrro=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.3/go.mod h1:eGQ1B63EQk4oPgIH6++g9Yv9VTrGEsVZKQN3rDos0YE=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.4 h1:ff2zj912ze2p/N8n4frx6n8lru6KDjVTFr1n5H17p6E=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.4/go.mod h1:eGQ1B63EQk4oPgIH6++g9Yv9VTrGEsVZKQN3rDos0YE=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.5 h1:k86Xl8HJzgaM43ssOB3SP4HGk0l3TRXESy4tQrVoJIw=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.5/go.mod h1:eGQ1B63EQk4oPgIH6++g9Yv9VTrGEsVZKQN3rDos0YE=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.6 h1:CY0DSQRIKkfiPVfQ0Dk6cvqv+MfLzDmYzxXRKFnd3RU=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.6/go.mod h1:eGQ1B63EQk4oPgIH6++g9Yv9VTrGEsVZKQN3rDos0YE=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.8 h1:p5uOAaUxHDufPeS2BrIC95iWi9era04dDgAFjQPFDYM=
+git.ali33.ru/fcg-xvii/curve/v2 v2.0.8/go.mod h1:eGQ1B63EQk4oPgIH6++g9Yv9VTrGEsVZKQN3rDos0YE=
+git.ali33.ru/fcg-xvii/go-tools v0.0.0-20220506161429-319953bb5590/go.mod h1:8XpQShSOR7fAiCJg56M2mhf1KxiqnTeGttW/CUuyyCk=
+git.ali33.ru/fcg-xvii/go-tools v0.0.0-20221003202615-4f03edf5cf03 h1:1ZnIuj6Z2f/Rv8TDSQuDBBwWCezEE5aZSBjo88tSIBE=
+git.ali33.ru/fcg-xvii/go-tools v0.0.0-20221003202615-4f03edf5cf03/go.mod h1:YbBhWFFNNQIKcRisQFnpVaN5KA+XHGImSU1Z/MuntqU=
+git.ali33.ru/fcg-xvii/metla v0.0.0-20220517153538-bd52ccf7e7e6 h1:w8JjrU2HLcqiD4TBib/DcyP/a3zT3ymsQOrhQk0Auz8=
+git.ali33.ru/fcg-xvii/metla v0.0.0-20220517153538-bd52ccf7e7e6/go.mod h1:lyRviMPacJ7rdLY0Hr8b9Q8kYmxqgwAUa+X8IoSrQ2w=
+git.ali33.ru/fcg-xvii/metla v0.0.0-20220925104102-c0394c741ec0 h1:9RlqbNu9JQNqPfFBtSFn6pRYDKefCHF1/DOMAGs0Tas=
+git.ali33.ru/fcg-xvii/metla v0.0.0-20220925104102-c0394c741ec0/go.mod h1:lyRviMPacJ7rdLY0Hr8b9Q8kYmxqgwAUa+X8IoSrQ2w=
+git.ali33.ru/fcg-xvii/mjs v0.0.0-20220517153042-199c5e0b2dcc/go.mod h1:f9ApGKec9HmiIR27bm1LsU+yRr5Vgi4wMvMFOXbIOro=
+git.ali33.ru/fcg-xvii/mjs v0.0.0-20220520114419-c93c27cfcaa1 h1:3pe8npIi2ByY+qAGh8nTId4KL/OWjSopKRrWF16eDoA=
+git.ali33.ru/fcg-xvii/mjs v0.0.0-20220520114419-c93c27cfcaa1/go.mod h1:f9ApGKec9HmiIR27bm1LsU+yRr5Vgi4wMvMFOXbIOro=
+git.ali33.ru/fcg-xvii/mjs v0.0.0-20221008153018-6dc4c41d564e h1:9gts3Asm6NAirL5yFKauqJYCdKY16N7qe06B2HU5YMg=
+git.ali33.ru/fcg-xvii/mjs v0.0.0-20221008153018-6dc4c41d564e/go.mod h1:dC19Z2W/l4mkNE076KC8iBmWSjbvkeyFK2zk6JUNyTw=
+git.ali33.ru/fcg-xvii/net v1.0.6 h1:+oBxhAJsjr9I/5Ub0pFEGaJcHCdo9io/Y0g4eal1WVs=
+git.ali33.ru/fcg-xvii/net v1.0.6/go.mod h1:ewqD/y8+XWGBZJtghC8v+Zn6lq105xJut2hPBs6CXSs=
+git.ali33.ru/fcg-xvii/net/v3 v3.2.0 h1:9eOGPP1HttkajmpaGJAYumo5h6nGeBOrQVQ5sAs94YQ=
+git.ali33.ru/fcg-xvii/net/v3 v3.2.0/go.mod h1:onmfJhthLc8AJBpxyQ8WH/bU3zwNQuJAuvRbaLYeUws=
+git.ali33.ru/fcg-xvii/net/v3 v3.2.1 h1:adMRkMb9n02K4ayJ5A1VFGyO9g6e8ruU2KfSimn3N8o=
+git.ali33.ru/fcg-xvii/net/v3 v3.2.1/go.mod h1:onmfJhthLc8AJBpxyQ8WH/bU3zwNQuJAuvRbaLYeUws=
+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/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
+github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
+github.com/dop251/goja v0.0.0-20220516123900-4418d4575a41/go.mod h1:TQJQ+ZNyFVvUtUEtCZxBhfWiH7RJqR3EivNmvD6Waik=
+github.com/dop251/goja v0.0.0-20220815083517-0c74f9139fd6 h1:xHdUVG+c8SWJnct16Z3QJOVlaYo3OwoJyamo6kR6OL0=
+github.com/dop251/goja v0.0.0-20220815083517-0c74f9139fd6/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs=
+github.com/dop251/goja v0.0.0-20221003171542-5ea1285e6c91 h1:1PfaQuGdeJVnHHQ0tg0Jw7MXagyqaAupJyk35/QM3I4=
+github.com/dop251/goja v0.0.0-20221003171542-5ea1285e6c91/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs=
+github.com/dop251/goja v0.0.0-20221019153710-09250e0eba20 h1:AxWn8phZA9tjgDGKyDRbHtI6nCBkDu8UH17FCpSHRPA=
+github.com/dop251/goja v0.0.0-20221019153710-09250e0eba20/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs=
+github.com/dop251/goja v0.0.0-20221024130056-0ad46a434ac5 h1:vecG6NrggTQGPjFrQndy8t2x3YZ1X9ReiU5EOus/ofg=
+github.com/dop251/goja v0.0.0-20221024130056-0ad46a434ac5/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs=
+github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
+github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM=
+github.com/fcg-xvii/go-tools v0.0.0-20220316201232-6d6629b9d1e7/go.mod h1:iqeLyAqB+RN0zxQTNk7yWI9dzy09Oc6yUk1m1vkdws0=
+github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
+github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
+github.com/jackc/pgx/v5 v5.0.0-beta.3/go.mod h1:QJ8xU09HYKHOccHeisi/6sXeRG4dd3AxuV7cmKET4WA=
+github.com/jackc/pgx/v5 v5.0.0-beta.5 h1:7H5vxAbAN3zpEif3dpdsXvbhfIUb2NVIogwoMNZjlPg=
+github.com/jackc/pgx/v5 v5.0.0-beta.5/go.mod h1:h6/rDxQ5OUUxMEeTJYC3HZ/6Rh6uPVD0zLsdODEcwps=
+github.com/jackc/pgx/v5 v5.0.3 h1:4flM5ecR/555F0EcnjdaZa6MhBU+nr0QbZIo5vaKjuM=
+github.com/jackc/pgx/v5 v5.0.3/go.mod h1:JBbvW3Hdw77jKl9uJrEDATUZIFM2VFPzRq4RWIhkF4o=
+github.com/jackc/puddle/v2 v2.0.0-beta.1/go.mod h1:itE7ZJY8xnoo0JqJEpSMprN0f+NQkMCuEV/N9j8h0oc=
+github.com/jackc/puddle/v2 v2.0.0-beta.2 h1:xhhtVfiDyh29TTvZPIvY5zld5YYMmA9ErRr+fjMkmE0=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
+github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+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/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+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 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/xlab/closer v1.0.0 h1:2o9/LUpwFzBa1RsHkH+4RPUKLJI6acUW3Go+xi6pOeY=
+github.com/xlab/closer v1.0.0/go.mod h1:Ff8YcUPbn5jju6nClrMCmJHQABM0S/obEK0za/1yVMk=
+github.com/xlab/closer v1.1.0 h1:yrDiOXjd/B7pZ3lZkl/EZ1gWrR2M2N5XpBnixynm4mc=
+github.com/xlab/closer v1.1.0/go.mod h1:Ff8YcUPbn5jju6nClrMCmJHQABM0S/obEK0za/1yVMk=
+golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
+golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg=
+golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220517181318-183a9ca12b87 h1:cCR+9mKLOGyX4Zx+uBZDXEDAQsvKQ/XbW4vreG5v1jU=
+golang.org/x/net v0.0.0-20220517181318-183a9ca12b87/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20221019024206-cb67ada4b0ad h1:Zx6wVVDwwNJFWXNIvDi7o952w3/1ckSwYk/7eykRmjM=
+golang.org/x/net v0.0.0-20221019024206-cb67ada4b0ad/go.mod h1:RpDiru2p0u2F0lLpEoqnP2+7xs0ifAuOcJ442g6GU2s=
+golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+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=

+ 16 - 0
html/index.html

@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>curve</title>
+        <script language="javascript" src="/java/socket.js"></script>
+        <script language="javascript" src="/java/main.js"></script>
+    </head>
+    <body>
+        <script language="javascript">
+            var addr = "{{ addr }}"
+            console.log(addr)
+        </script>
+        <h1>Curve</h1>
+        <div id="curves"></div>
+    </body>
+</html>

+ 48 - 0
html/java/main.js

@@ -0,0 +1,48 @@
+// main
+document.addEventListener("DOMContentLoaded", function(event) { 
+
+    let conn = new Conn(addr, {
+        incoming: function(mes) {
+            let data = mes.data()
+            console.log('incoming', data)
+        },
+        connected: function() {
+            console.log('connected')
+            // interface can be enabled
+            conn.sendMessage({
+                'command': 'method',
+                'random_num': "1000000",
+            }, function(rData) {
+                console.log('method', rData)
+            })
+        }
+    })
+
+
+
+    /*
+    let api = new API(addr)
+
+    api.curveInit(
+        "2",
+        "4",
+        "10000",
+        function(data) {
+            console.log('curve-init', data)
+        }
+    )
+
+    api.curves()
+    */
+
+    window.onbeforeunload = function(e) {
+        var message = "Закрыть программу?";
+	    if (typeof e == "undefined") {
+		    e = window.event;
+	    }
+	    if (e) {
+		    e.returnValue = message;
+	    }
+	    return message;
+    }
+});

+ 133 - 0
html/java/socket.js

@@ -0,0 +1,133 @@
+function Message(obj, conn) {
+    
+    this.isResponsable = function() {
+        return obj.id >= 0
+    }
+
+    this.sendResponse = function(data) {
+        conn.send({
+            id: obj.id,
+            is_response: true,
+            data: data
+        })
+    }
+
+    this.data = function() {
+        return obj.data
+    }
+
+    return this
+}
+
+/* 
+{
+    connected: function
+    сlosed: function
+    incoming: function
+} 
+*/
+function Conn(addr, callback = {}) {
+    
+    self = this
+    let socket = null
+    let connected = false
+    let rStore = {}
+    let idCounter = 0, idMax = Math.pow(2, 62)
+    let mQueue = []
+
+    function nextID() {
+        idCounter += 1
+        if (idCounter == idMax)
+            idCounter = 0
+        return idCounter
+    }
+
+    function connect() {
+        socket = new WebSocket("ws://" + addr + "/api")
+
+        socket.onopen = function(e) {
+            connected = true
+            if (callback.connected != null)
+                callback.connected()
+            //console.log('connected', mQueue)
+            mQueue.forEach(function(obj) {
+                self.sendMessage(obj.obj, obj.rCallback, obj.deadline)
+            })
+            mQueue = []
+        }
+    
+        socket.onclose = function(e) {
+            //console.log('close...')
+            connected = false
+            if (callback.closed != null)
+                callback.closed()
+            setTimeout(function() {
+                self.reconnect()
+            }, 3000)
+        }
+    
+        socket.onmessage = function(e) {
+            let mObj = JSON.parse(e.data)
+            //console.log(mObj)
+            if (mObj.is_response) {
+                //console.log('response')
+                let rCall = rStore[mObj.id]
+                //console.log('rc', rCall, rStore)
+                if (rCall) {
+                    clearTimeout(rCall.cancel)
+                    delete rStore[mObj.id]
+                    rCall.callback(mObj.data)
+                    //console.log(rStore)
+                }
+            } else {
+                let m = new Message(mObj, self)
+                callback.incoming(m)
+            }
+        }
+    }
+
+    this.reconnect = function() {
+        //console.log('reconnect', connected)
+        connect()
+    }
+
+    function send (obj) {
+        if (!connected) {
+            return
+        }
+        socket.send(JSON.stringify(obj))
+    }
+
+    this.sendMessage = function(obj, rCallback, deadline = 30000) {
+        if (!connected) {
+            mQueue.push({
+                obj: obj,
+                rCallback: rCallback,
+                deadline: deadline
+            })
+            return
+        }
+        if (deadline == 0) {
+            send({
+                id: id,
+                data: obj,
+            })
+        } else {
+            let id = nextID()
+            send({
+                id: id,
+                data: obj,
+            })
+            let cancel = setTimeout(function() {
+                delete rStore[id]
+            }, deadline)
+            rStore[id] = {
+                cancel: cancel,
+                callback: rCallback,
+            }
+        }
+    }
+
+    connect()
+    return self
+}

+ 47 - 0
main.go

@@ -0,0 +1,47 @@
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"git.ali33.ru/fcg-xvii/go-tools/text/config"
+	_ "git.ali33.ru/fcg-xvii/go-tools/text/config/ini"
+	"git.ali33.ru/fcg-xvii/net/v3/http/server"
+)
+
+var (
+	listen    = "127.0.0.1:33775"
+	debugMode = false
+	downTime  = 5
+)
+
+func main() {
+	appConf, err := config.FromFile("ini", "config.ini")
+	if err == nil {
+		listen = appConf.ValueDefault("listen", listen).(string)
+		debugMode = appConf.ValueDefault("debug_mode", debugMode).(bool)
+		downTime = appConf.ValueDefault("downtime", downTime).(int)
+	}
+
+	log.Println("listen", listen)
+	log.Println("debug_mode", debugMode)
+	log.Println("downtime", downTime)
+
+	if !debugMode {
+		openURI(fmt.Sprintf("http://%s", listen))
+	}
+
+	// запуск сервера
+	conf := server.ConfigDefault()
+	conf.Addr = listen
+	conf.App = NewApplication(listen)
+
+	serv := server.NewServerHTTP(conf)
+
+	go serv.Start(func(s server.Server, started bool, err error) {
+		log.Println(s, started, err)
+	})
+
+	mainChan := make(chan struct{})
+	<-mainChan
+}

+ 53 - 0
message.go

@@ -0,0 +1,53 @@
+package main
+
+import (
+	"errors"
+
+	"git.ali33.ru/fcg-xvii/go-tools/json"
+)
+
+func messageError(text string) json.Map {
+	return json.Map{
+		"error": true,
+		"text":  text,
+	}
+}
+
+func MessageFromMap(jm json.Map, cl *WSClient) *Message {
+	res := &Message{
+		client: cl,
+		id:     jm.Int("id", -1),
+		data:   jm.Map("data", json.Map{}),
+	}
+	return res
+}
+
+type Message struct {
+	client *WSClient
+	id     int64
+	data   json.Map
+}
+
+func (s *Message) Client() *WSClient {
+	return s.client
+}
+
+func (s *Message) Data() json.Map {
+	return s.data
+}
+
+func (s *Message) IsResponsable() bool {
+	return s.id >= 0
+}
+
+func (s *Message) SendResponse(data json.Map) error {
+	if !s.IsResponsable() {
+		return errors.New("response is not supported")
+	}
+	m := json.Map{
+		"is_response": true,
+		"id":          s.id,
+		"data":        data,
+	}
+	return s.client.SendData(m)
+}

+ 245 - 0
method.go

@@ -0,0 +1,245 @@
+package main
+
+import (
+	"context"
+	"log"
+	"math/big"
+	"sync"
+	"time"
+
+	"git.ali33.ru/fcg-xvii/curve/v2"
+	"git.ali33.ru/fcg-xvii/curve/v2/dhellman"
+	"git.ali33.ru/fcg-xvii/curve/v2/elgamal"
+	"git.ali33.ru/fcg-xvii/curve/v2/tools"
+	"git.ali33.ru/fcg-xvii/go-tools/json"
+)
+
+func EventSingle(Type, method string, contextID int) *Event {
+	res := &Event{
+		ContextID: contextID,
+		Type:      Type,
+		Value:     json.Map{},
+	}
+	if len(method) > 0 {
+		res.Value["method"] = method
+	}
+	return res
+}
+
+type Event struct {
+	ContextID int
+	Type      string
+	IsError   bool
+	Value     json.Map
+}
+
+func (s *Event) Map() json.Map {
+	return json.Map{
+		"context_id": s.ContextID,
+		"type":       "event",
+		"name":       s.Type,
+		"is_error":   s.IsError,
+		"data":       s.Value,
+	}
+
+}
+
+func (s *Event) MarshalJSON() ([]byte, error) {
+	return s.Map().JSON(), nil
+}
+
+func (s *Event) String() string {
+	return s.Map().JSONPrettyString()
+}
+
+func MethodExec(p1, p2 curve.KeyPair, ch chan<- *Event, ctx context.Context, message, method string, contextID int) {
+	// генерация ключей
+	t := time.Now()
+	encoded, _ := p1.MessageEncode([]byte(message), p2.KeyPublic())
+	select {
+	case <-ctx.Done():
+		return
+	default:
+		ch <- &Event{
+			ContextID: contextID,
+			Type:      "Сообщение зашифровано пользователем 1",
+			Value: json.Map{
+				"method":  method,
+				"text":    message,
+				"encoded": encoded,
+				"time":    int64(time.Since(t) / time.Millisecond),
+			},
+		}
+	}
+	t = time.Now()
+	decoded, _ := p2.MessageDecode(encoded, p1.KeyPublic())
+	select {
+	case <-ctx.Done():
+		return
+	default:
+		ch <- &Event{
+			ContextID: contextID,
+			Type:      "Сообщение расшифровано пользователем 2",
+			Value: json.Map{
+				"method":  method,
+				"text":    message,
+				"decoded": string(decoded),
+				"time":    int64(time.Since(t) / time.Millisecond),
+			},
+		}
+	}
+	// Атака посредника.
+	ch <- EventSingle("Атака посредника. Запущен подбор ключа", method, contextID)
+	t = time.Now()
+	if aPair, err := p2.KeyPublic().Attack(ctx); err != nil {
+		ch <- &Event{
+			ContextID: contextID,
+			Type:      "Атака посредника",
+			IsError:   true,
+			Value: json.Map{
+				"method": method,
+				"text":   err.Error(),
+			},
+		}
+	} else {
+		decoded, _ = aPair.MessageDecode(encoded, p1.KeyPublic())
+		ch <- &Event{
+			ContextID: contextID,
+			Type:      "Атака посредника. Ключ найден",
+			Value: json.Map{
+				"method":  method,
+				"pair":    p2,
+				"cracked": aPair,
+				"time":    int64(time.Since(t) / time.Millisecond),
+				"source":  message,
+				"decoded": string(decoded),
+			},
+		}
+	}
+}
+
+func MethodCurve(randNum *big.Int, message string, ctx context.Context, contextID int) <-chan *Event {
+	ch := make(chan *Event)
+	go func() {
+		defer close(ch)
+		// Поиск параметров кривой
+		a, b, p := tools.CurveRandomParams(randNum)
+		select {
+		case <-ctx.Done():
+			return
+		default:
+			ch <- &Event{
+				ContextID: contextID,
+				Type:      "Параметры кривой определены",
+				Value: json.Map{
+					"a": a,
+					"b": b,
+					"p": p,
+				},
+			}
+		}
+		ch <- EventSingle("Инициализация кривой", "", contextID)
+		t := time.Now()
+		c, err := curve.NewCurve(a, b, p, ctx)
+		if err != nil {
+			ch <- &Event{
+				ContextID: contextID,
+				Type:      "Инициализация кривой",
+				IsError:   true,
+				Value: json.Map{
+					"text": err.Error(),
+				},
+			}
+			return
+		}
+		ch <- &Event{
+			ContextID: contextID,
+			Type:      "Кривая инициализирована",
+			Value: json.Map{
+				"g":    c.G(),
+				"time": int64(time.Since(t) / time.Millisecond),
+			},
+		}
+		var wg sync.WaitGroup
+		wg.Add(2)
+		// метод Диффи-Хеллмана
+		go func() {
+			defer wg.Done()
+			// Генерация ключей
+			ch <- EventSingle("Генерация пар ключей", "Диффи-Хеллман", contextID)
+			t := time.Now()
+			p1, _ := dhellman.CurveKeyPair(c)
+			p2, _ := dhellman.CurveKeyPair(c)
+			select {
+			case <-ctx.Done():
+				return
+			default:
+				ch <- &Event{
+					ContextID: contextID,
+					Type:      "Пары ключей сгенерированы",
+					Value: json.Map{
+						"method": "Диффи-Хеллман",
+						"u1":     p1,
+						"u2":     p2,
+						"time":   int64(time.Since(t) / time.Millisecond),
+					},
+				}
+			}
+			MethodExec(p1, p2, ch, ctx, message, "Диффи-Хеллман", contextID)
+		}()
+		// метод Эль-Гамаля
+		go func() {
+			defer wg.Done()
+			// Генерация таблицы
+			ch <- EventSingle("Построение таблицы (символ) -> (точка на кривой) для шифрования/расшифровки сообщений", "Эль-Гамаль", contextID)
+			t := time.Now()
+			cc, err := elgamal.NewCurve(c, ctx)
+			if err != nil {
+				ch <- &Event{
+					ContextID: contextID,
+					Type:      "Построение таблицы (символ) -> (точка на кривой) для шифрования/расшифровки сообщений",
+					IsError:   true,
+					Value: json.Map{
+						"method": "Эль-Гамаль",
+						"text":   err.Error(),
+					},
+				}
+				return
+			}
+			ch <- &Event{
+				ContextID: contextID,
+				Type:      "Тиблица символов построена",
+				Value: json.Map{
+					"method": "Эль-Гамаль",
+					"time":   int64(time.Since(t) / time.Millisecond),
+					"curve":  cc.Map(),
+				},
+			}
+			ch <- EventSingle("Генерация пар ключей", "Эль-Гамаль", contextID)
+			t = time.Now()
+			p1, _ := elgamal.CurveKeyPair(cc, ctx)
+			p2, _ := elgamal.CurveKeyPair(cc, ctx)
+			select {
+			case <-ctx.Done():
+				return
+			default:
+				ch <- &Event{
+					ContextID: contextID,
+					Type:      "Пары ключей сгенерированы",
+					Value: json.Map{
+						"method": "Эль-Гамаль",
+						"u1":     p1,
+						"u2":     p2,
+						"time":   int64(time.Since(t) / time.Millisecond),
+					},
+				}
+			}
+			MethodExec(p1, p2, ch, ctx, message, "Эль-Гамаль", contextID)
+		}()
+		wg.Wait()
+		ch <- EventSingle("Все работы завершены.", "", contextID)
+		log.Println("FINISH")
+		contextStore.Delete(contextID)
+	}()
+	return ch
+}

+ 31 - 0
tools.go

@@ -0,0 +1,31 @@
+package main
+
+import (
+	"fmt"
+	"math/big"
+	"math/rand"
+)
+
+func checkBigInt(mes *Message, field string) (*big.Int, bool) {
+	mData := mes.Data()
+	res, check := new(big.Int).SetString(mData.StringVal(field, ""), 10)
+	if !check {
+		mes.SendResponse(
+			messageError(fmt.Sprintf("ожидается числовое значение поля [ %s ]", field)),
+		)
+		return nil, false
+	}
+	return res, true
+}
+
+func randHex() string {
+	src := make([]byte, 16)
+	rand.Read(src)
+	return fmt.Sprintf("%x", src)
+}
+
+/*
+func randomCurve() (a, b *big.Int) {
+	curve.NewCurve()
+}
+*/