From bb5a342863ee2b25373e9bb96722a6921bb92b7b Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 13 Oct 2026 17:02:20 +0200 Subject: [PATCH] Every value an approval sets is in the note, whole where the sender is proven; the note is kept whole (issue 383) The review of mesh-controller #304: a proposal of more than three keys showed only the names of the rest, and its Details could carry no value, so Approve bound values the operator never saw. The router now shows an ask's WholeDetails in the note in place of its Details on a kind that proves who answers, held to the secret rule alone, and refuses an ask whose whole details carry a secret's shape. Telegram keeps the note whole when a message is too long, cutting the body first and saying so, and escapes the note as every other part. SDK at mesh-sdk f474544. --- modules/claude-code/go.mod | 2 +- modules/claude-code/go.sum | 2 + modules/desk-channel/go.mod | 2 +- modules/desk-channel/go.sum | 2 + modules/mesh-knowledge/go.mod | 2 +- modules/mesh-knowledge/go.sum | 2 + modules/messenger/README.md | 4 +- modules/messenger/cmd/messenger/asks.go | 35 +++++++++--- modules/messenger/cmd/messenger/holder.go | 10 +++- modules/messenger/cmd/messenger/whole_test.go | 55 +++++++++++++++++++ modules/messenger/go.mod | 2 +- modules/messenger/go.sum | 2 + modules/telegram/README.md | 2 +- modules/telegram/cmd/telegram/render.go | 25 ++++----- modules/telegram/cmd/telegram/render_test.go | 26 ++++++--- modules/telegram/go.mod | 2 +- modules/telegram/go.sum | 2 + 17 files changed, 137 insertions(+), 40 deletions(-) diff --git a/modules/claude-code/go.mod b/modules/claude-code/go.mod index 6562a740..3ae9efa8 100644 --- a/modules/claude-code/go.mod +++ b/modules/claude-code/go.mod @@ -2,6 +2,6 @@ module claude-code go 1.25.0 -require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629 +require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d require gopkg.in/yaml.v3 v3.0.1 diff --git a/modules/claude-code/go.sum b/modules/claude-code/go.sum index f09ac821..e31a5b11 100644 --- a/modules/claude-code/go.sum +++ b/modules/claude-code/go.sum @@ -2,6 +2,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.13 h1:Su4JYpZ+zhNovkGA2DgxiZdcuHpjw2tPJzc/7P git.novox.be/novox/mesh-sdk/go v0.1.13/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629 h1:7TYFV1Q6Mcz+lsLP/sds87tysET4rKCn3rRIQV8gNmA= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d h1:HEJyqorKktrkJPeeJdwEo0kdrJjH3fm/YVS9MGftCqY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/modules/desk-channel/go.mod b/modules/desk-channel/go.mod index c3cc8428..fc97ce5b 100644 --- a/modules/desk-channel/go.mod +++ b/modules/desk-channel/go.mod @@ -2,4 +2,4 @@ module deskchannel go 1.22 -require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629 +require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d diff --git a/modules/desk-channel/go.sum b/modules/desk-channel/go.sum index b5bb9911..0df2f17b 100644 --- a/modules/desk-channel/go.sum +++ b/modules/desk-channel/go.sum @@ -2,3 +2,5 @@ git.novox.be/novox/mesh-sdk/go v0.1.10 h1:EHhnPRrkw7/CSQAqRsxYnTvlTZ3dI02IPO6WSm git.novox.be/novox/mesh-sdk/go v0.1.10/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629 h1:7TYFV1Q6Mcz+lsLP/sds87tysET4rKCn3rRIQV8gNmA= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d h1:HEJyqorKktrkJPeeJdwEo0kdrJjH3fm/YVS9MGftCqY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= diff --git a/modules/mesh-knowledge/go.mod b/modules/mesh-knowledge/go.mod index 5e41d704..0d489090 100644 --- a/modules/mesh-knowledge/go.mod +++ b/modules/mesh-knowledge/go.mod @@ -3,7 +3,7 @@ module mesh-knowledge go 1.25.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d github.com/jackc/pgx/v5 v5.11.0 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.51.0 diff --git a/modules/mesh-knowledge/go.sum b/modules/mesh-knowledge/go.sum index 06f07d11..fdc7fe21 100644 --- a/modules/mesh-knowledge/go.sum +++ b/modules/mesh-knowledge/go.sum @@ -2,6 +2,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011091942-4cf45b5ca0cf h1:ED/+RszK git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011091942-4cf45b5ca0cf/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629 h1:7TYFV1Q6Mcz+lsLP/sds87tysET4rKCn3rRIQV8gNmA= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d h1:HEJyqorKktrkJPeeJdwEo0kdrJjH3fm/YVS9MGftCqY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/modules/messenger/README.md b/modules/messenger/README.md index 0ead976d..7a70a347 100644 --- a/modules/messenger/README.md +++ b/modules/messenger/README.md @@ -136,7 +136,9 @@ condition's message. A warning kept quiet is also said once after a day. explanation alone — a summary, then at most three points (`asks.Glance`; an ask that does not hold to it is shown and said in the log). Everything else is the message's note (`asks.Message.Note`), which a channel shows apart and smaller: who asked and when, with what happens if nobody answers; what each answer does; where else it is answered; -and the asker's Details (who proposed it, a fingerprint, how to read it whole). Answered, the message is one line — +and the asker's Details (who proposed it, a fingerprint, how to read it whole) — on a kind that proves who answers +and was given the ask's answers, its Details whole (`asks.Ask.WholeDetails`): every value an approval sets, held to +the secret rule alone, as the whole words are. Answered, the message is one line — "You chose Approve at 16:06 on Telegram · " — and the router's word on the asker is its note. **An ask's values are shown whole where the sender is proven** (hq issue 383). An ask may carry its explanation diff --git a/modules/messenger/cmd/messenger/asks.go b/modules/messenger/cmd/messenger/asks.go index 04ac5d04..c98c7ace 100644 --- a/modules/messenger/cmd/messenger/asks.go +++ b/modules/messenger/cmd/messenger/asks.go @@ -172,22 +172,39 @@ func (h *Holder) openAsk(r *Record) *AskRecord { // rule, is shown. The ask's state does not matter: a message edited to say how the ask ended still shows what // was approved. func (h *Holder) wholeOf(r *Record, kind string) string { + if a := h.provenAsk(r, kind); a != nil { + return a.Whole + } + return "" +} + +// wholeDetailsOf is an ask's Details with their values whole (asks.Ask.WholeDetails), shown in the note in place of +// its Details where wholeOf would show its whole words: every value an approval sets, so the operator reads exactly +// what they approve (the review of mesh-controller #304). Empty elsewhere. +func (h *Holder) wholeDetailsOf(r *Record, kind string) string { + if a := h.provenAsk(r, kind); a != nil { + return a.WholeDetails + } + return "" +} + +// provenAsk is the ask of an ask's own record when the kind proves who answers and was given the ask's answers; +// nil otherwise. +func (h *Holder) provenAsk(r *Record, kind string) *asks.Ask { if r == nil || r.Origin != "ask" || r.Ask == "" || kind == "" || h.Bench == nil { - return "" + return nil } e := h.askOf(r.Ask) - if e == nil || e.rec.Ask.Whole == "" { - return "" - } - if !h.Bench.Promises(kind, "verified-sender") { - return "" + if e == nil || !h.Bench.Promises(kind, "verified-sender") { + return nil } for _, tk := range e.rec.Tickets { if tk.Kind == kind { - return e.rec.Ask.Whole + a := e.rec.Ask + return &a } } - return "" + return nil } // carriers are the kinds that can carry an answer of a level now: ready, offering a choice, and for @@ -474,7 +491,7 @@ func (h *Holder) TakeAsk(verb, asker string, body json.RawMessage) error { // The whole words are shown only where the sender is proven (wholeOf), so a path or an address may stand // in them; a secret's shape leaves the mesh nowhere, and an ask carrying one is refused as a whole, never // shown with its explanation alone (novox/hq issue 383). - if refusal, ok := CheckSecret(a.Whole); !ok { + if refusal, ok := CheckSecret(a.Whole + "\n" + a.WholeDetails); !ok { h.refuseAsk(asker, a, "its whole words carry "+refusal.String()+", which may not leave the mesh on any channel: withhold it") return nil } diff --git a/modules/messenger/cmd/messenger/holder.go b/modules/messenger/cmd/messenger/holder.go index 8b3f448a..29795a39 100644 --- a/modules/messenger/cmd/messenger/holder.go +++ b/modules/messenger/cmd/messenger/holder.go @@ -885,11 +885,17 @@ func (h *Holder) sayOn(r *Record, what, kind string) Message { note = append(note, line) } } - for _, line := range strings.Split(strings.TrimSpace(rec.Ask.Details), "\n") { + // On a kind that proves who answers, the Details whole (issue 383): every value an approval sets, held to + // the secret rule alone, as the whole words are. + details, passes := rec.Ask.Details, Check + if wd := h.wholeDetailsOf(r, kind); wd != "" { + details, passes = wd, CheckSecret + } + for _, line := range strings.Split(strings.TrimSpace(details), "\n") { if line = strings.TrimSpace(line); line == "" { continue } - if refusal, ok := Check(line); !ok { + if refusal, ok := passes(line); !ok { line = "(a line carrying " + refusal.What + " is withheld here)" } note = append(note, line) diff --git a/modules/messenger/cmd/messenger/whole_test.go b/modules/messenger/cmd/messenger/whole_test.go index a094cfe2..092b7b9b 100644 --- a/modules/messenger/cmd/messenger/whole_test.go +++ b/modules/messenger/cmd/messenger/whole_test.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "strings" "testing" "time" @@ -153,3 +154,57 @@ func TestAnAskWhoseWholeWordsCarryASecretIsRefused(t *testing.T) { } } } + +// The review of mesh-controller #304: a proposal of five keys, one of them 300 characters long, shows two keys at +// a glance; every key and every value, whole, is in the note on a kind that proves who answers, so the operator can +// read exactly what Approve sets. The desk, which proves nothing, shows them masked. +func TestEveryKeyAndItsWholeValueIsInTheNoteWhereTheSenderIsProven(t *testing.T) { + h, tg, _, c, store, _ := newRouter(t) + link(h, store, c, "42", c.now().Add(-2*time.Hour)) + var long strings.Builder + long.WriteString("library=/storage") + for i := 0; long.Len() < 300; i++ { + long.WriteString(fmt.Sprintf("/album-%02d", i)) + } + value := long.String()[:300] + keys := map[string]string{"a": "1", "b": "2", "c": "3", "d": "4", "shares": value} + masked := map[string]string{"a": "1", "b": "2", "c": "3", "d": "4", "shares": "library=‹path›"} + lines := func(values map[string]string) string { + var out []string + for _, k := range []string{"a", "b", "c", "d", "shares"} { + out = append(out, "+ "+k+": "+values[k]) + } + return strings.Join(out, "\n") + } + a := proposalAsk(c, "s-9") + a.Explanation = "Changes 5 setting(s) of mounts on shanks.\n+ a: 1\n+ b: 2\nand 3 more, each whole below: c, d, shares" + a.Whole = "" + a.Details = "Fingerprint 1234 5678 9abc def0 1234 5678.\n" + lines(masked) + a.WholeDetails = "Fingerprint 1234 5678 9abc def0 1234 5678.\n" + lines(keys) + submit(t, h, "mesh-controller", a) + settle(h, c) + if len(tg.sends) != 1 { + t.Fatalf("telegram got %d messages", len(tg.sends)) + } + phone := tg.sends[0] + for k, v := range keys { + if !strings.Contains(phone.Note, "+ "+k+": "+v) { + t.Errorf("the phone's note lacks %s whole:\n%s", k, phone.Note) + } + } + if strings.Contains(phone.Body, "/storage") || strings.Count(phone.Body, "\n") > 3 { + t.Errorf("the body is not the glance:\n%s", phone.Body) + } + desk := h.sayOn(h.open["ask.mesh-controller.s-9"], "raised", "desktop") + if strings.Contains(desk.Text(), "/storage") || !strings.Contains(desk.Note, "+ shares: library=‹path›") { + t.Errorf("the desk shows a value whole, or not every key:\n%s", desk.Note) + } + // A secret's shape in the whole details refuses the ask as a whole. + b := proposalAsk(c, "s-10") + b.WholeDetails = "+ token: ghp_abcdefghijklmnopqrstuvwxyz0123456789" + submit(t, h, "mesh-controller", b) + settle(h, c) + if _, kept := store.asks["mesh-controller.s-10"]; kept || len(tg.sends) != 1 { + t.Errorf("an ask whose whole details carry a secret was taken") + } +} diff --git a/modules/messenger/go.mod b/modules/messenger/go.mod index d471d086..d03c1405 100644 --- a/modules/messenger/go.mod +++ b/modules/messenger/go.mod @@ -2,4 +2,4 @@ module messenger go 1.22 -require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629 +require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d diff --git a/modules/messenger/go.sum b/modules/messenger/go.sum index 75e71c63..f3f5b3ae 100644 --- a/modules/messenger/go.sum +++ b/modules/messenger/go.sum @@ -2,3 +2,5 @@ git.novox.be/novox/mesh-sdk/go v0.1.13 h1:Su4JYpZ+zhNovkGA2DgxiZdcuHpjw2tPJzc/7P git.novox.be/novox/mesh-sdk/go v0.1.13/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629 h1:7TYFV1Q6Mcz+lsLP/sds87tysET4rKCn3rRIQV8gNmA= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d h1:HEJyqorKktrkJPeeJdwEo0kdrJjH3fm/YVS9MGftCqY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= diff --git a/modules/telegram/README.md b/modules/telegram/README.md index c12fe8eb..f8821915 100644 --- a/modules/telegram/README.md +++ b/modules/telegram/README.md @@ -31,7 +31,7 @@ as the operator. | | fixed here | |---|---| | D1 | up to 4096 characters arrive whole; longer is cut and the cut said | -| issues 383, 639 | shown formatted (HTML), never reworded: the title bold, the body as it is with a key line in monospace, the note apart in a blockquote collapsed to its first lines; `<`, `>` and `&` escaped first, so nothing in the words is read as markup. A tap is compared by the plain words, whitespace aside | +| issues 383, 639 | shown formatted (HTML), never reworded: the title bold, the body as it is with a key line in monospace, the note apart in a blockquote collapsed to its first lines, kept whole when a message is too long (the body is cut first, and the cut said); `<`, `>` and `&` escaped first, so nothing in the words is read as markup. A tap is compared by the plain words, whitespace aside | | D4 | a warning or a clearing arrives without sound; an urgent message or a question rings | | D5 | a rate limit is waited out as told | | D6 | a refusal is a permanent failure, said to the router and not retried; an edit to the same text is a success | diff --git a/modules/telegram/cmd/telegram/render.go b/modules/telegram/cmd/telegram/render.go index 37f8af5f..9bdd257f 100644 --- a/modules/telegram/cmd/telegram/render.go +++ b/modules/telegram/cmd/telegram/render.go @@ -35,8 +35,10 @@ func escape(s string) string { // shown is a message's three parts as the chat carries them. type shown struct{ title, body, note string } -// partsOf is a message's parts, cut so that its plain words fit MaxLength and the cut said (D1): the note is cut -// first, then the body. The bound is on the words, as Telegram's is on the text once its markup is read. +// partsOf is a message's parts, cut so that its plain words fit MaxLength and the cut said (D1). The body is cut +// first: the note carries what each answer does and every value an approval sets, so it is kept whole as long as +// the title and the note fit; only then is the note cut, and that said too. The bound is on the words, as +// Telegram's is on the text once its markup is read. func partsOf(m asks.Message) shown { s := shown{title: strings.TrimSpace(m.Title), body: strings.TrimSpace(m.Body), note: strings.TrimSpace(m.Note)} over := utf8.RuneCountInString(s.plain()) - MaxLength @@ -44,21 +46,16 @@ func partsOf(m asks.Message) shown { return s } mark := utf8.RuneCountInString(cutNote) - cut := func(text string, by int) string { - r := []rune(text) - keep := max(len(r)-by-mark, 0) - return string(r[:keep]) + cutNote - } - if utf8.RuneCountInString(s.note) > over+mark { - s.note = cut(s.note, over) + if r := []rune(s.body); len(r) >= over+mark { + s.body = string(r[:len(r)-over-mark]) + cutNote return s } - s.note = "" - keep := max(MaxLength-utf8.RuneCountInString(s.title)-1-mark, 0) - if r := []rune(s.body); keep < len(r) { - s.body = string(r[:keep]) + // The body cannot make room alone: what is left of it is the cut's word, and the note is cut too. + s.body = strings.TrimPrefix(cutNote, "\n") + if over = utf8.RuneCountInString(s.plain()) - MaxLength; over > 0 { + r := []rune(s.note) + s.note = string(r[:max(len(r)-over-mark, 0)]) + cutNote } - s.body += cutNote return s } diff --git a/modules/telegram/cmd/telegram/render_test.go b/modules/telegram/cmd/telegram/render_test.go index 5ae2f9eb..a2658313 100644 --- a/modules/telegram/cmd/telegram/render_test.go +++ b/modules/telegram/cmd/telegram/render_test.go @@ -61,16 +61,26 @@ func TestTheADR0343AskFitsAGlance(t *testing.T) { } } -// A long note is cut before the body is, and the cut said; a body too long loses the note and is cut itself. -func TestALongNoteIsCutBeforeTheBody(t *testing.T) { - m := asks.Message{Title: "t", Body: "the summary", Note: strings.Repeat("n", 5000)} +// The note is kept whole when the message is too long: the body is cut first and the cut said; only a note that +// cannot fit beside the title is cut, and that said too (the review of mesh-catalog #278). +func TestALongBodyIsCutBeforeTheNote(t *testing.T) { + m := asks.Message{Title: "t", Body: strings.Repeat("b", 5000), Note: "+ shares: media=/storage/media\nFingerprint 1234."} s := partsOf(m) - if s.body != "the summary" || !strings.HasSuffix(s.note, cutNote) || len([]rune(s.plain())) != MaxLength { + if s.note != m.Note || !strings.HasSuffix(s.body, cutNote) || len([]rune(s.plain())) != MaxLength { + t.Errorf("note %q, body ends %q, %d characters", s.note, s.body[len(s.body)-20:], len([]rune(s.plain()))) + } + m.Body, m.Note = "the summary", strings.Repeat("n", 5000) + s = partsOf(m) + if !strings.HasSuffix(s.note, cutNote) || !strings.Contains(s.body, "cut here") || len([]rune(s.plain())) != MaxLength { t.Errorf("body %q, note ends %q, %d characters", s.body, s.note[len(s.note)-20:], len([]rune(s.plain()))) } - m.Body = strings.Repeat("b", 5000) - s = partsOf(m) - if s.note != "" || !strings.HasSuffix(s.body, cutNote) || len([]rune(s.plain())) != MaxLength { - t.Errorf("note %d, %d characters", len(s.note), len([]rune(s.plain()))) +} + +// A '<', '>' or '&' in the note is escaped like any other part: it neither breaks the blockquote nor injects. +func TestTheNoteIsEscaped(t *testing.T) { + got := partsOf(asks.Message{Title: "t", Note: "Asked by x & y "}).html() + want := "t\n\n
Asked by <b>x</b> & y </blockquote><i>
" + if got != want { + t.Errorf("%q", got) } } diff --git a/modules/telegram/go.mod b/modules/telegram/go.mod index ab5e7c21..f27b7fe6 100644 --- a/modules/telegram/go.mod +++ b/modules/telegram/go.mod @@ -2,4 +2,4 @@ module telegram go 1.22 -require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629 +require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d diff --git a/modules/telegram/go.sum b/modules/telegram/go.sum index b5bb9911..0df2f17b 100644 --- a/modules/telegram/go.sum +++ b/modules/telegram/go.sum @@ -2,3 +2,5 @@ git.novox.be/novox/mesh-sdk/go v0.1.10 h1:EHhnPRrkw7/CSQAqRsxYnTvlTZ3dI02IPO6WSm git.novox.be/novox/mesh-sdk/go v0.1.10/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629 h1:7TYFV1Q6Mcz+lsLP/sds87tysET4rKCn3rRIQV8gNmA= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013141520-9588871d6629/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d h1:HEJyqorKktrkJPeeJdwEo0kdrJjH3fm/YVS9MGftCqY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013145622-f4745447ba6d/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=