Expose UpdateUsers on the inbounds whose underlying service already implements it
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 38.1k
- Forks
- 4.6k
- Avg merge
- 19d 15h
- Merged PRs (30d)
- 1
Description
This is not a request for a user management API. SagerNet/sing-box#2621 and SagerNet/sing-box#3022 covered that and I have read the answers -- no API surface, no config option, no daemon endpoint is being asked for here.
The narrower thing: vless.Service[T], vmess.Service[T], trojan.Service[T], hysteria.Service[T], hysteria2.Service[T], tuic.Service[T] and anytls.Service all implement UpdateUsers. sing-box holds each one in an unexported field and the Inbound wrappers do not forward the method, so from outside protocol/ it is unreachable. shadowsocks.MultiInbound is the exception -- it forwards it for the SSM API. protocol/tuic/inbound.go already calls UpdateUsers itself, once, inside NewInbound, to seed the user list.
For anything that embeds sing-box as a library, changing a single user therefore means removing the inbound and adding it back. That drops every live session on that inbound, and for the QUIC-based protocols it tears down the QUIC connection as well.
The alternative -- the one 2S-UI (https://github.com/shenaba/2s-ui , GPLv3, a sing-box server panel) actually took -- is to copy protocol//inbound.go verbatim into a local package so the service field becomes reachable, and attach UpdateUsers there. Seven files: anytls, hysteria, hysteria2, trojan, tuic, vless, vmess. They keep compiling after a sing-box bump while silently running the old implementation, so CI diffs them against the version in go.mod on every build.
Two changes would remove the need for that:
UpdateUsers on those seven Inbound types, forwarding to the service. Nothing else -- no new option, no behaviour change unless it is called.
Service[int] -> Service[string] in six of them (anytls's service is not generic). Indexing users by list position is correct as long as the list is never rewritten, which is true today. UpdateUsers rewrites it under live sessions, and then position is not a stable identity: removing one user shifts every later one, which misattributes traffic to the wrong name and can index past the end of the name slice. Keying by name is what we ended up with after hitting exactly that.
I will write the PR with tests if you are open to it. If you would rather not carry this, closing the issue is a fine answer -- I just do not want to send a few hundred lines you have already decided against.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read protocol/anytls/inbound.go, protocol/hysteria/inbound.go, protocol/hysteria2/inbound.go, protocol/trojan/inbound.go, protocol/tuic/inbound.go, protocol/vless/inbound.go, and protocol/vmess/inbound.go, along with their UpdateUsers implementations. Add the requested forwarding methods and review the Service[int] to Service[string] mapping for live-session updates. Done means all seven inbounds expose UpdateUsers without new configuration or API surfaces, with tests covering the change.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- networking
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100