fix(group-translate): recognize admins across the lid/phone split, and let the backend be configured - #61
Merged
rmyndharis merged 1 commit intoAug 1, 2026
Conversation
…d let the backend be configured WhatsApp delivers a group message's author under a privacy id (`…@lid`) while getGroupInfo lists participants under phone ids (`…@c.us`). The two carry unrelated user numbers, so widEquals could never relate them: every admin failed the check and only the group `owner` — which WhatsApp reports in the author's own dialect — was recognized. In a group created by the bot's own number even that failed, since the owner's messages are fromMe and never reach the coordinator, leaving the group with no working administrator. When the direct comparison finds nothing, the author is now resolved to its canonical `@c.us` identity through getContactById and compared again. That is the same identity `/tr grant` stores for a controller named by phone number, so delegation starts working too. The call is spent only on what would otherwise be a denial, and memoized afterwards — a lid/phone binding does not change. Resolution widens recognition, never permission: an author who resolves to someone outside both lists is still refused, and an unresolvable one denies. Separately, `net.allow` pinned the backend to `localhost:7001`, so pointing the plugin at any other LibreTranslate meant editing the manifest and rebuilding the zip — while the free-form `libretranslateUrl` field implied otherwise and silently failed. It now allows loopback on any port and, through allowConfigHosts, whatever https host the operator configures, matching how voice-transcription already handles its backend.
rmyndharis
deleted the
fix/group-translate-lid-admin-and-configurable-backend
branch
August 1, 2026 08:25
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two independent defects, both confirmed against a live OpenWA 0.12.1 host.
1. Group admins were refused their own commands
WhatsApp delivers the author of a group message under a privacy id (
…@lid), whilegetGroupInforeturns the participant list under phone ids (…@c.us). Those two carry unrelated user numbers, so no normalization relates them —widEqualssays as much in its own docblock. Every admin failed the comparison and/tr on,/tr setlang,/tr grantand the rest were silently denied.Only the group's
ownerwas ever recognized, because WhatsApp reports that one in the author's own dialect. And in a group created by the bot's own number, even that did not help: the owner's messages arefromMeand never reach the coordinator. The result was a group with no working administrator at all.Observed live — a member the group API reported as
6281770008896@c.us admin=Truewas refused/tr on, while/tr setlangfrom the same person echoed their identity back as148004841455867@lid.Change. When the direct comparison finds nothing, the author is resolved to its canonical identity and compared again.
getContactByIdis the bridge: handed a@lid, the engine looks the contact up in its own store and returns it keyed by its canonical<phone>@c.usid.(
numberis not the bridge — for a lid contact that is the lid's own user part, which is exactly the value that cannot be compared.idis.)The same identity is what
/tr grantstores for a controller named by phone number, so delegation starts working too — it was broken in precisely the same way.Three properties this deliberately keeps:
2. The LibreTranslate backend could not be configured without repackaging
net.allowwas pinned tolocalhost:7001, so pointing the plugin at any other instance meant editing the manifest and rebuilding the.zip— while the free-formlibretranslateUrlconfig field implied otherwise, and every other value failed silently at the plugin's own allowlist. For a plugin installed from the catalog that is not a workable setup path.It now allows loopback on any port as shipped, and admits whatever host the operator configures via
net.allowConfigHosts— which the gateway accepts over https only. That is the shapevoice-transcriptionalready uses for its backend, so the two now behave the same way.The one case still outside it is a plain-http backend on a non-loopback host (a Docker service name). That still needs the manifest edited, because the gateway deliberately ignores a non-https config-supplied host; the README says so rather than leaving it to be discovered.
A loopback or private address continues to require
SSRF_ALLOWED_HOSTSon the OpenWA host — a separate control the plugin cannot influence, documented in Setup and Security.Tests
Six new cases: an admin recognized behind a
@lidauthor; a delegated controller named by phone recognized the same way; a genuine non-admin still refused after resolution; no round-trip spent when the direct comparison already authorizes; the resolution memoized across commands; and an unresolvable author denying rather than failing open.Removing the resolution step fails three of them. Full suite 535/535, typecheck and catalog check clean.