An ask reads at a glance on the phone: a headline, a summary and its points, the rest in a note (issues 383 and 639)
The operator would not read the Telegram ask for ADR 0343: thirty plain lines, every clause on one, no bold, no summary. A settings proposal was the same wall of text, its values masked so the approval was blind. - messenger: an ask's message is the asker's headline and explanation alone; who asked and when, what each answer does, the expiry, where else it is answered and the asker's Details travel as the message's note (asks.Message.Note). Answered, the message is one line, "You chose Approve at 16:06 on Telegram · <headline>". An explanation that does not read at a glance (asks.Glance) is shown and logged. On a kind that proves who answers, an ask's values are shown whole (asks.Ask.Whole), held to the secret rule alone (from the earlier work on issue 383, #178). - telegram: every message in HTML, never reworded: the title bold, a key line monospace, the note apart in a collapsed blockquote; markup escaped. A tap is compared by its words, whitespace aside, and a message shown before is still compared by the digest it was kept under. - desk-channel: the note follows the body. - mesh-knowledge: a record that needs the operator carries a brief (headline, summary, at most three points), the 30th per-record rule; its ask shows the brief and never the clauses. An ask made before is composed again as it was asked (form), so its warrant still holds. - claude-code: an instructions proposal's explanation is one summary line (the proposer's, or the module's), its text in the Details; a question's context is at most 300 characters and its recommendation one point. Older proposals and questions keep their form. The SDK is pinned at mesh-sdk 9588871 (fix/639-an-ask-reads-at-a-glance), which adds Message.Note and asks.Glance.
This commit is contained in:
@@ -65,6 +65,59 @@ func Check(text string) (Refusal, bool) {
|
||||
return Refusal{"address", "a hardware address"}, false
|
||||
case reIPv6.MatchString(text):
|
||||
return Refusal{"address", "an IPv6 address"}, false
|
||||
}
|
||||
if refusal, ok := secretShape(text); !ok {
|
||||
return refusal, false
|
||||
}
|
||||
if reWinPath.MatchString(text) {
|
||||
return Refusal{"path", "a drive path"}, false
|
||||
}
|
||||
if refusal, ok := randomRun(text); !ok {
|
||||
return refusal, false
|
||||
}
|
||||
for _, word := range strings.FieldsFunc(text, func(r rune) bool {
|
||||
return unicode.IsSpace(r) || strings.ContainsRune("\"'`()[]{}<>,;|", r)
|
||||
}) {
|
||||
w := strings.TrimRight(word, ".:!?")
|
||||
if isPath(w) {
|
||||
return Refusal{"path", "a file path"}, false
|
||||
}
|
||||
if isHostName(w) {
|
||||
return Refusal{"address", "a host name"}, false
|
||||
}
|
||||
}
|
||||
return Refusal{}, true
|
||||
}
|
||||
|
||||
// CheckSecret says whether a text carries a secret's shape — the one class that leaves the mesh nowhere. It is
|
||||
// what an ask's whole words (asks.Ask.Whole, novox/hq issue 383) are held to: on a kind that proves who answers,
|
||||
// a path or an address is what the operator approves and may be shown, a secret never. A path is read as one:
|
||||
// a run with a slash in it is judged piece by piece between the slashes, so "/mnt/Photos_2024/Jochen" is a
|
||||
// path and not a random string (the review of 2026-10-10); the named shapes — a key block, a signed token, a
|
||||
// bot token, a known token shape, a value given to a secret's name, a long hexadecimal string — hold whatever
|
||||
// the run holds.
|
||||
func CheckSecret(text string) (Refusal, bool) {
|
||||
if refusal, ok := secretShape(text); !ok {
|
||||
return refusal, false
|
||||
}
|
||||
return randomRunOutsidePaths(text)
|
||||
}
|
||||
|
||||
// randomRunOutsidePaths is randomRun with each run that holds a slash judged by its pieces between the slashes.
|
||||
func randomRunOutsidePaths(text string) (Refusal, bool) {
|
||||
for _, run := range reRun.FindAllString(text, -1) {
|
||||
for _, piece := range strings.Split(run, "/") {
|
||||
if len(piece) >= 20 && looksRandom(piece) {
|
||||
return Refusal{"secret", "a long random-looking string"}, false
|
||||
}
|
||||
}
|
||||
}
|
||||
return Refusal{}, true
|
||||
}
|
||||
|
||||
// secretShape is the secret shapes a pattern names.
|
||||
func secretShape(text string) (Refusal, bool) {
|
||||
switch {
|
||||
case rePEM.MatchString(text):
|
||||
return Refusal{"secret", "a key block"}, false
|
||||
case reJWT.MatchString(text):
|
||||
@@ -77,25 +130,17 @@ func Check(text string) (Refusal, bool) {
|
||||
return Refusal{"secret", "a value given to a secret's name"}, false
|
||||
case reHex.MatchString(text):
|
||||
return Refusal{"secret", "a long hexadecimal string"}, false
|
||||
case reWinPath.MatchString(text):
|
||||
return Refusal{"path", "a drive path"}, false
|
||||
}
|
||||
return Refusal{}, true
|
||||
}
|
||||
|
||||
// randomRun is a long unbroken run of characters spread as a random string's are.
|
||||
func randomRun(text string) (Refusal, bool) {
|
||||
for _, run := range reRun.FindAllString(text, -1) {
|
||||
if looksRandom(run) {
|
||||
return Refusal{"secret", "a long random-looking string"}, false
|
||||
}
|
||||
}
|
||||
for _, word := range strings.FieldsFunc(text, func(r rune) bool {
|
||||
return unicode.IsSpace(r) || strings.ContainsRune("\"'`()[]{}<>,;|", r)
|
||||
}) {
|
||||
w := strings.TrimRight(word, ".:!?")
|
||||
if isPath(w) {
|
||||
return Refusal{"path", "a file path"}, false
|
||||
}
|
||||
if isHostName(w) {
|
||||
return Refusal{"address", "a host name"}, false
|
||||
}
|
||||
}
|
||||
return Refusal{}, true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user