Repository navigation
v0.0.1-alpha.6
Pre-release
Pre-release
What three reviews of the first day's code found. Two of these were leaks.
Security
- The bot token no longer escapes through an API error. Telegram never echoes
the request, but a proxy or a sidecar answering 404 or 502 in its place
quotes the request URI -- which contains the token -- and that string reached
log lines and, in branchy, a database column. Descriptions and raw bodies are
now redacted like URLs are. - The token no longer escapes through a wrapped
fs.PathErroreither. A local
server names each bot's directory after its token, so every local-file error
carried it inPathError.Patheven though the message itself was clean. The
error keeps its identity --errors.Is(err, fs.ErrNotExist)still works --
with the path scrubbed. - Symlinks can no longer escape
<filesRoot>/<token>. Cleaning a path stops a
..and nothing stopped a link, on a directory written by another process
and shared with every other bot. Both sides are resolved before comparison.
Fixed
- A 2xx answer carrying
ok=falseis an*APIErroragain, with its error
code, description, retry_after and body. Telegram does not answer that way,
but a proxy does -- and callers classify failures by type, so it was arriving
as an untyped error that skipped every recovery path. Classification now
reads Telegram's own code when the HTTP status does not carry it, which also
fixesanswerCallbackQuery,setMyCommandsandeditMessageText, none of
which checkedokat all. ErrUnexpectedResultseparates "the call failed" from "the call was made and
the answer is unreadable". A bot whose notification was delivered should not
queue it again because the receipt did not parse; a bot that needs the new
message's id genuinely cannot continue. Such an answer is also no longer
retried -- it will not parse differently the second time -- and it now names
the method.- A failed download no longer leaves a truncated file behind.
os.Create
truncates before the size is known, and a caller that finds a file where an
error was reported will read it. Preflightwaits through the failures a starting server actually produces.
It gave up on any API answer, which meant a 502 from a proxy in front of a
booting server was fatal; only a refused connection was ever waited out.Needs.Waitbounds the whole check rather than only the pauses inside it.
With the retries insidegetMe, a 30-second budget could run for minutes,
and an operator sizes a restart policy on that number.- A probe survives a dropped connection. An ordinary POST is not replayed
because a lost answer may still have been acted on, but a probe carries an
empty body, so one reset connection was reading as "the server lacks this
method". Proberefuses to guess when the server answers 401, 403, or a 404 that is
not Telegram's. Those say the server never looked at the method, and
reporting it present defeats the point of a guard that exists to refuse.- A POST that is asked to wait longer than its caller can afford now returns
both facts: what Telegram answered and that the wait was cut short. It used
to return only the context error, losing the 429 and its retry_after. - The JSON contract matches the API: fields Telegram always sends marshal at
their zero value -- an accidentally empty button label was being sent as a
button with no label at all -- and anUpdateno longer marshals three
nulls.File.file_unique_id,Video.width/height,
ChatMemberUpdated.date/old_chat_memberandCallbackQuery.chat_instance
are modeled;CallbackQuery.datais optional, as it is in the API.
Changed
Event.RetriedbecameEvent.Retryable. It was computed from the error
alone and claimed another attempt would follow, which was untrue for a 5xx on
a POST and for the last attempt of an exhausted GET.
Documentation
docs/limitations.mdlists what the package cannot express yet -- multipart
uploads, per-chat command scopes, inline-message editing, an extensible probe
list -- so the next consumer meets them on paper rather than in the source.