]> Cypherpunks.ru repositories - nncp.git/blobdiff - src/cfg.go
Fixed freq.chunked calculation
[nncp.git] / src / cfg.go
index dabb510a9a3e552b6cf646ce42e5aef9d868c5ac..d46bf0e08ce8dbbed9dfddef04f6fc722100b02e 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2021 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@ import (
        "bytes"
        "encoding/json"
        "errors"
+       "fmt"
        "log"
        "os"
        "path"
@@ -30,7 +31,7 @@ import (
        "github.com/gorhill/cronexpr"
        "github.com/hjson/hjson-go"
        "golang.org/x/crypto/ed25519"
-       "golang.org/x/crypto/ssh/terminal"
+       "golang.org/x/term"
 )
 
 const (
@@ -51,8 +52,8 @@ type NodeJSON struct {
        ExchPub  string              `json:"exchpub"`
        SignPub  string              `json:"signpub"`
        NoisePub *string             `json:"noisepub,omitempty"`
-       Exec     map[string][]string `json:"exec,omitempty"`
        Incoming *string             `json:"incoming,omitempty"`
+       Exec     map[string][]string `json:"exec,omitempty"`
        Freq     *NodeFreqJSON       `json:"freq,omitempty"`
        Via      []string            `json:"via,omitempty"`
        Calls    []CallJSON          `json:"calls,omitempty"`
@@ -73,7 +74,7 @@ type NodeFreqJSON struct {
 }
 
 type CallJSON struct {
-       Cron           string
+       Cron           string  `json:"cron"`
        Nice           *string `json:"nice,omitempty"`
        Xx             *string `json:"xx,omitempty"`
        RxRate         *int    `json:"rxrate,omitempty"`
@@ -81,6 +82,17 @@ type CallJSON struct {
        Addr           *string `json:"addr,omitempty"`
        OnlineDeadline *uint   `json:"onlinedeadline,omitempty"`
        MaxOnlineTime  *uint   `json:"maxonlinetime,omitempty"`
+       WhenTxExists   bool    `json:"when-tx-exists,omitempty"`
+       NoCK           bool    `json:"nock,omitempty"`
+       MCDIgnore      bool    `json:"mcd-ignore,omitempty"`
+
+       AutoToss       bool `json:"autotoss,omitempty"`
+       AutoTossDoSeen bool `json:"autotoss-doseen,omitempty"`
+       AutoTossNoFile bool `json:"autotoss-nofile,omitempty"`
+       AutoTossNoFreq bool `json:"autotoss-nofreq,omitempty"`
+       AutoTossNoExec bool `json:"autotoss-noexec,omitempty"`
+       AutoTossNoTrns bool `json:"autotoss-notrns,omitempty"`
+       AutoTossNoArea bool `json:"autotoss-noarea,omitempty"`
 }
 
 type NodeOurJSON struct {
@@ -89,13 +101,13 @@ type NodeOurJSON struct {
        ExchPrv  string `json:"exchprv"`
        SignPub  string `json:"signpub"`
        SignPrv  string `json:"signprv"`
-       NoisePrv string `json:"noiseprv"`
        NoisePub string `json:"noisepub"`
+       NoisePrv string `json:"noiseprv"`
 }
 
 type FromToJSON struct {
-       From string
-       To   string
+       From string `json:"from"`
+       To   string `json:"to"`
 }
 
 type NotifyJSON struct {
@@ -104,17 +116,36 @@ type NotifyJSON struct {
        Exec map[string]*FromToJSON `json:"exec,omitempty"`
 }
 
+type AreaJSON struct {
+       Id  string  `json:"id"`
+       Pub *string `json:"pub,omitempty"`
+       Prv *string `json:"prv,omitempty"`
+
+       Subs []string `json:"subs"`
+
+       Incoming *string             `json:"incoming,omitempty"`
+       Exec     map[string][]string `json:"exec,omitempty"`
+
+       AllowUnknown bool `json:"allow-unknown,omitempty"`
+}
+
 type CfgJSON struct {
-       Spool string `json:"spool"`
-       Log   string `json:"log"`
-       Umask string `json:"umask",omitempty`
+       Spool string  `json:"spool"`
+       Log   string  `json:"log"`
+       Umask *string `json:"umask,omitempty"`
+
+       OmitPrgrs bool `json:"noprogress,omitempty"`
+       NoHdr     bool `json:"nohdr,omitempty"`
 
-       OmitPrgrs bool `json:"noprogress",omitempty`
+       MCDRxIfis []string       `json:"mcd-listen,omitempty"`
+       MCDTxIfis map[string]int `json:"mcd-send,omitempty"`
 
        Notify *NotifyJSON `json:"notify,omitempty"`
 
        Self  *NodeOurJSON        `json:"self"`
        Neigh map[string]NodeJSON `json:"neigh"`
+
+       Areas map[string]AreaJSON `json:"areas,omitempty"`
 }
 
 func NewNode(name string, cfg NodeJSON) (*Node, error) {
@@ -160,7 +191,7 @@ func NewNode(name string, cfg NodeJSON) (*Node, error) {
        }
 
        var freqPath *string
-       freqChunked := int64(MaxFileSize)
+       var freqChunked int64
        var freqMinSize int64
        freqMaxSize := int64(MaxFileSize)
        if cfg.Freq != nil {
@@ -260,12 +291,7 @@ func NewNode(name string, cfg NodeJSON) (*Node, error) {
                        onlineDeadline = time.Duration(*callCfg.OnlineDeadline) * time.Second
                }
 
-               var maxOnlineTime time.Duration
-               if callCfg.MaxOnlineTime != nil {
-                       maxOnlineTime = time.Duration(*callCfg.MaxOnlineTime) * time.Second
-               }
-
-               calls = append(calls, &Call{
+               call := Call{
                        Cron:           expr,
                        Nice:           nice,
                        Xx:             xx,
@@ -273,8 +299,23 @@ func NewNode(name string, cfg NodeJSON) (*Node, error) {
                        TxRate:         txRate,
                        Addr:           addr,
                        OnlineDeadline: onlineDeadline,
-                       MaxOnlineTime:  maxOnlineTime,
-               })
+               }
+
+               if callCfg.MaxOnlineTime != nil {
+                       call.MaxOnlineTime = time.Duration(*callCfg.MaxOnlineTime) * time.Second
+               }
+               call.WhenTxExists = callCfg.WhenTxExists
+               call.NoCK = callCfg.NoCK
+               call.MCDIgnore = callCfg.MCDIgnore
+               call.AutoToss = callCfg.AutoToss
+               call.AutoTossDoSeen = callCfg.AutoTossDoSeen
+               call.AutoTossNoFile = callCfg.AutoTossNoFile
+               call.AutoTossNoFreq = callCfg.AutoTossNoFreq
+               call.AutoTossNoExec = callCfg.AutoTossNoExec
+               call.AutoTossNoTrns = callCfg.AutoTossNoTrns
+               call.AutoTossNoArea = callCfg.AutoTossNoArea
+
+               calls = append(calls, &call)
        }
 
        node := Node{
@@ -373,11 +414,60 @@ func NewNodeOur(cfg *NodeOurJSON) (*NodeOur, error) {
        return &node, nil
 }
 
-func CfgParse(data []byte) (*Ctx, error) {
+func NewArea(ctx *Ctx, name string, cfg *AreaJSON) (*Area, error) {
+       areaId, err := AreaIdFromString(cfg.Id)
+       if err != nil {
+               return nil, err
+       }
+       subs := make([]*NodeId, 0, len(cfg.Subs))
+       for _, s := range cfg.Subs {
+               node, err := ctx.FindNode(s)
+               if err != nil {
+                       return nil, err
+               }
+               subs = append(subs, node.Id)
+       }
+       area := Area{
+               Name:     name,
+               Id:       areaId,
+               Subs:     subs,
+               Exec:     cfg.Exec,
+               Incoming: cfg.Incoming,
+       }
+       if cfg.Pub != nil {
+               pub, err := Base32Codec.DecodeString(*cfg.Pub)
+               if err != nil {
+                       return nil, err
+               }
+               if len(pub) != 32 {
+                       return nil, errors.New("Invalid pub size")
+               }
+               area.Pub = new([32]byte)
+               copy(area.Pub[:], pub)
+       }
+       if cfg.Prv != nil {
+               if area.Pub == nil {
+                       return nil, fmt.Errorf("area %s: prv requires pub presence", name)
+               }
+               prv, err := Base32Codec.DecodeString(*cfg.Prv)
+               if err != nil {
+                       return nil, err
+               }
+               if len(prv) != 32 {
+                       return nil, errors.New("Invalid prv size")
+               }
+               area.Prv = new([32]byte)
+               copy(area.Prv[:], prv)
+       }
+       area.AllowUnknown = cfg.AllowUnknown
+       return &area, nil
+}
+
+func CfgParse(data []byte) (*CfgJSON, error) {
        var err error
-       if bytes.Compare(data[:8], MagicNNCPBv3[:]) == 0 {
+       if bytes.Compare(data[:8], MagicNNCPBv3.B[:]) == 0 {
                os.Stderr.WriteString("Passphrase:")
-               password, err := terminal.ReadPassword(0)
+               password, err := term.ReadPassword(0)
                if err != nil {
                        log.Fatalln(err)
                }
@@ -386,6 +476,10 @@ func CfgParse(data []byte) (*Ctx, error) {
                if err != nil {
                        return nil, err
                }
+       } else if bytes.Compare(data[:8], MagicNNCPBv2.B[:]) == 0 {
+               log.Fatalln(MagicNNCPBv2.TooOld())
+       } else if bytes.Compare(data[:8], MagicNNCPBv1.B[:]) == 0 {
+               log.Fatalln(MagicNNCPBv1.TooOld())
        }
        var cfgGeneral map[string]interface{}
        if err = hjson.Unmarshal(data, &cfgGeneral); err != nil {
@@ -396,14 +490,17 @@ func CfgParse(data []byte) (*Ctx, error) {
                return nil, err
        }
        var cfgJSON CfgJSON
-       if err = json.Unmarshal(marshaled, &cfgJSON); err != nil {
-               return nil, err
-       }
+       err = json.Unmarshal(marshaled, &cfgJSON)
+       return &cfgJSON, err
+}
+
+func Cfg2Ctx(cfgJSON *CfgJSON) (*Ctx, error) {
        if _, exists := cfgJSON.Neigh["self"]; !exists {
                return nil, errors.New("self neighbour missing")
        }
        var self *NodeOur
        if cfgJSON.Self != nil {
+               var err error
                self, err = NewNodeOur(cfgJSON.Self)
                if err != nil {
                        return nil, err
@@ -418,8 +515,8 @@ func CfgParse(data []byte) (*Ctx, error) {
                return nil, errors.New("Log path must be absolute")
        }
        var umaskForce *int
-       if cfgJSON.Umask != "" {
-               r, err := strconv.ParseUint(cfgJSON.Umask, 8, 16)
+       if cfgJSON.Umask != nil {
+               r, err := strconv.ParseUint(*cfgJSON.Umask, 8, 16)
                if err != nil {
                        return nil, err
                }
@@ -430,14 +527,21 @@ func CfgParse(data []byte) (*Ctx, error) {
        if cfgJSON.OmitPrgrs {
                showPrgrs = false
        }
+       hdrUsage := true
+       if cfgJSON.NoHdr {
+               hdrUsage = false
+       }
        ctx := Ctx{
                Spool:      spoolPath,
                LogPath:    logPath,
                UmaskForce: umaskForce,
                ShowPrgrs:  showPrgrs,
+               HdrUsage:   hdrUsage,
                Self:       self,
                Neigh:      make(map[NodeId]*Node, len(cfgJSON.Neigh)),
                Alias:      make(map[string]*NodeId),
+               MCDRxIfis:  cfgJSON.MCDRxIfis,
+               MCDTxIfis:  cfgJSON.MCDTxIfis,
        }
        if cfgJSON.Notify != nil {
                if cfgJSON.Notify.File != nil {
@@ -476,5 +580,15 @@ func CfgParse(data []byte) (*Ctx, error) {
                        )
                }
        }
+       ctx.AreaId2Area = make(map[AreaId]*Area, len(cfgJSON.Areas))
+       ctx.AreaName2Id = make(map[string]*AreaId, len(cfgJSON.Areas))
+       for name, areaJSON := range cfgJSON.Areas {
+               area, err := NewArea(&ctx, name, &areaJSON)
+               if err != nil {
+                       return nil, err
+               }
+               ctx.AreaId2Area[*area.Id] = area
+               ctx.AreaName2Id[name] = area.Id
+       }
        return &ctx, nil
 }