]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/cfg.go
NNCP is expanded to "Node to Node copy"
[nncp.git] / src / cypherpunks.ru / nncp / cfg.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2017 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package nncp
20
21 import (
22         "errors"
23         "path"
24
25         "golang.org/x/crypto/ed25519"
26         "gopkg.in/yaml.v2"
27 )
28
29 var (
30         DefaultCfgPath      string = "/usr/local/etc/nncp.yaml"
31         DefaultSendmailPath string = "/usr/sbin/sendmail"
32 )
33
34 type NodeYAML struct {
35         Id       string
36         ExchPub  string
37         SignPub  string
38         NoisePub string
39         Incoming *string  `incoming,omitempty`
40         Freq     *string  `freq,omitempty`
41         Via      []string `via,omitempty`
42
43         Addrs map[string]string `addrs,omitempty`
44 }
45
46 type NodeOurYAML struct {
47         Id       string
48         ExchPub  string
49         ExchPrv  string
50         SignPub  string
51         SignPrv  string
52         NoisePrv string
53         NoisePub string
54 }
55
56 type FromToYAML struct {
57         From string
58         To   string
59 }
60
61 type NotifyYAML struct {
62         File *FromToYAML `file,omitempty`
63         Freq *FromToYAML `freq,omitempty`
64 }
65
66 type CfgYAML struct {
67         Self  NodeOurYAML
68         Neigh map[string]NodeYAML
69
70         Spool    string
71         Log      string
72         Sendmail []string
73         Notify   *NotifyYAML `notify,omitempty`
74 }
75
76 func NewNode(name string, yml NodeYAML) (*Node, error) {
77         nodeId, err := NodeIdFromString(yml.Id)
78         if err != nil {
79                 return nil, err
80         }
81
82         exchPub, err := FromBase32(yml.ExchPub)
83         if err != nil {
84                 return nil, err
85         }
86         if len(exchPub) != 32 {
87                 return nil, errors.New("Invalid exchPub size")
88         }
89
90         signPub, err := FromBase32(yml.SignPub)
91         if err != nil {
92                 return nil, err
93         }
94         if len(signPub) != ed25519.PublicKeySize {
95                 return nil, errors.New("Invalid signPub size")
96         }
97
98         noisePub, err := FromBase32(yml.NoisePub)
99         if err != nil {
100                 return nil, err
101         }
102         if len(noisePub) != 32 {
103                 return nil, errors.New("Invalid noisePub size")
104         }
105
106         var incoming *string
107         if yml.Incoming != nil {
108                 inc := path.Clean(*yml.Incoming)
109                 if !path.IsAbs(inc) {
110                         return nil, errors.New("Incoming path must be absolute")
111                 }
112                 incoming = &inc
113         }
114
115         var freq *string
116         if yml.Freq != nil {
117                 fr := path.Clean(*yml.Freq)
118                 if !path.IsAbs(fr) {
119                         return nil, errors.New("Freq path must be absolute")
120                 }
121                 freq = &fr
122         }
123
124         node := Node{
125                 Name:     name,
126                 Id:       nodeId,
127                 ExchPub:  new([32]byte),
128                 SignPub:  ed25519.PublicKey(signPub),
129                 NoisePub: new([32]byte),
130                 Incoming: incoming,
131                 Freq:     freq,
132                 Addrs:    yml.Addrs,
133         }
134         copy(node.ExchPub[:], exchPub)
135         copy(node.NoisePub[:], noisePub)
136         return &node, nil
137 }
138
139 func NewNodeOur(yml NodeOurYAML) (*NodeOur, error) {
140         id, err := NodeIdFromString(yml.Id)
141         if err != nil {
142                 return nil, err
143         }
144
145         exchPub, err := FromBase32(yml.ExchPub)
146         if err != nil {
147                 return nil, err
148         }
149         if len(exchPub) != 32 {
150                 return nil, errors.New("Invalid exchPub size")
151         }
152
153         exchPrv, err := FromBase32(yml.ExchPrv)
154         if err != nil {
155                 return nil, err
156         }
157         if len(exchPrv) != 32 {
158                 return nil, errors.New("Invalid exchPrv size")
159         }
160
161         signPub, err := FromBase32(yml.SignPub)
162         if err != nil {
163                 return nil, err
164         }
165         if len(signPub) != ed25519.PublicKeySize {
166                 return nil, errors.New("Invalid signPub size")
167         }
168
169         signPrv, err := FromBase32(yml.SignPrv)
170         if err != nil {
171                 return nil, err
172         }
173         if len(signPrv) != ed25519.PrivateKeySize {
174                 return nil, errors.New("Invalid signPrv size")
175         }
176
177         noisePub, err := FromBase32(yml.NoisePub)
178         if err != nil {
179                 return nil, err
180         }
181         if len(noisePub) != 32 {
182                 return nil, errors.New("Invalid noisePub size")
183         }
184
185         noisePrv, err := FromBase32(yml.NoisePrv)
186         if err != nil {
187                 return nil, err
188         }
189         if len(noisePrv) != 32 {
190                 return nil, errors.New("Invalid noisePrv size")
191         }
192
193         node := NodeOur{
194                 Id:       id,
195                 ExchPub:  new([32]byte),
196                 ExchPrv:  new([32]byte),
197                 SignPub:  ed25519.PublicKey(signPub),
198                 SignPrv:  ed25519.PrivateKey(signPrv),
199                 NoisePub: new([32]byte),
200                 NoisePrv: new([32]byte),
201         }
202         copy(node.ExchPub[:], exchPub)
203         copy(node.ExchPrv[:], exchPrv)
204         copy(node.NoisePub[:], noisePub)
205         copy(node.NoisePrv[:], noisePrv)
206         return &node, nil
207 }
208
209 func (nodeOur *NodeOur) ToYAML() string {
210         yml := NodeOurYAML{
211                 Id:       nodeOur.Id.String(),
212                 ExchPub:  ToBase32(nodeOur.ExchPub[:]),
213                 ExchPrv:  ToBase32(nodeOur.ExchPrv[:]),
214                 SignPub:  ToBase32(nodeOur.SignPub[:]),
215                 SignPrv:  ToBase32(nodeOur.SignPrv[:]),
216                 NoisePub: ToBase32(nodeOur.NoisePub[:]),
217                 NoisePrv: ToBase32(nodeOur.NoisePrv[:]),
218         }
219         raw, err := yaml.Marshal(&yml)
220         if err != nil {
221                 panic(err)
222         }
223         return string(raw)
224 }
225
226 func CfgParse(data []byte) (*Ctx, error) {
227         var cfgYAML CfgYAML
228         err := yaml.Unmarshal(data, &cfgYAML)
229         if err != nil {
230                 return nil, err
231         }
232         self, err := NewNodeOur(cfgYAML.Self)
233         if err != nil {
234                 return nil, err
235         }
236         spoolPath := path.Clean(cfgYAML.Spool)
237         if !path.IsAbs(spoolPath) {
238                 return nil, errors.New("Spool path must be absolute")
239         }
240         logPath := path.Clean(cfgYAML.Log)
241         if !path.IsAbs(logPath) {
242                 return nil, errors.New("Log path must be absolute")
243         }
244         ctx := Ctx{
245                 Spool:    spoolPath,
246                 LogPath:  logPath,
247                 Self:     self,
248                 Neigh:    make(map[NodeId]*Node, len(cfgYAML.Neigh)),
249                 Alias:    make(map[string]*NodeId),
250                 Sendmail: cfgYAML.Sendmail,
251         }
252         if cfgYAML.Notify != nil {
253                 if cfgYAML.Notify.File != nil {
254                         ctx.NotifyFile = cfgYAML.Notify.File
255                 }
256                 if cfgYAML.Notify.Freq != nil {
257                         ctx.NotifyFreq = cfgYAML.Notify.Freq
258                 }
259         }
260         vias := make(map[NodeId][]string)
261         for name, neighYAML := range cfgYAML.Neigh {
262                 neigh, err := NewNode(name, neighYAML)
263                 if err != nil {
264                         return nil, err
265                 }
266                 ctx.Neigh[*neigh.Id] = neigh
267                 if _, already := ctx.Alias[name]; already {
268                         return nil, errors.New("Node names conflict")
269                 }
270                 ctx.Alias[name] = neigh.Id
271                 vias[*neigh.Id] = neighYAML.Via
272         }
273         for neighId, viasRaw := range vias {
274                 for _, viaRaw := range viasRaw {
275                         foundNodeId, err := ctx.FindNode(viaRaw)
276                         if err != nil {
277                                 return nil, err
278                         }
279                         ctx.Neigh[neighId].Via = append(
280                                 ctx.Neigh[neighId].Via,
281                                 foundNodeId.Id,
282                         )
283                 }
284         }
285         return &ctx, nil
286 }