mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
feat(identity): add unified user identity with canonical platform:id format
Introduce SenderInfo struct and pkg/identity package to standardize user identification across all channels. Each channel now constructs structured sender info (platform, platformID, canonicalID, username, displayName) instead of ad-hoc string IDs. Allow-list matching supports all legacy formats (numeric ID, @username, id|username) plus the new canonical "platform:id" format. Session key resolution also handles canonical peerIDs for backward-compatible identity link matching.
This commit is contained in:
@@ -163,6 +163,15 @@ func resolveLinkedPeerID(identityLinks map[string][]string, channel, peerID stri
|
||||
scopedCandidate := fmt.Sprintf("%s:%s", channel, strings.ToLower(peerID))
|
||||
candidates[scopedCandidate] = true
|
||||
}
|
||||
|
||||
// If peerID is already in canonical "platform:id" format, also add the
|
||||
// bare ID part as a candidate for backward compatibility with identity_links
|
||||
// that use raw IDs (e.g. "123" instead of "telegram:123").
|
||||
if idx := strings.Index(rawCandidate, ":"); idx > 0 && idx < len(rawCandidate)-1 {
|
||||
bareID := rawCandidate[idx+1:]
|
||||
candidates[bareID] = true
|
||||
}
|
||||
|
||||
if len(candidates) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -115,6 +115,51 @@ func TestBuildAgentPeerSessionKey_IdentityLink(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveLinkedPeerID_CanonicalPeerID(t *testing.T) {
|
||||
// When peerID is already in canonical "platform:id" format,
|
||||
// it should match identity_links that use the bare ID.
|
||||
links := map[string][]string{
|
||||
"john": {"123"},
|
||||
}
|
||||
got := resolveLinkedPeerID(links, "telegram", "telegram:123")
|
||||
if got != "john" {
|
||||
t.Errorf("resolveLinkedPeerID with canonical peerID = %q, want %q", got, "john")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveLinkedPeerID_CanonicalInLinks(t *testing.T) {
|
||||
// When identity_links contain canonical IDs and peerID is canonical too
|
||||
links := map[string][]string{
|
||||
"john": {"telegram:123", "discord:456"},
|
||||
}
|
||||
got := resolveLinkedPeerID(links, "telegram", "telegram:123")
|
||||
if got != "john" {
|
||||
t.Errorf("resolveLinkedPeerID canonical in links = %q, want %q", got, "john")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveLinkedPeerID_BarePeerIDMatchesCanonicalLink(t *testing.T) {
|
||||
// When peerID is bare "123" and links have "telegram:123",
|
||||
// the scoped candidate "telegram:123" should match.
|
||||
links := map[string][]string{
|
||||
"john": {"telegram:123"},
|
||||
}
|
||||
got := resolveLinkedPeerID(links, "telegram", "123")
|
||||
if got != "john" {
|
||||
t.Errorf("resolveLinkedPeerID bare peer matches canonical link = %q, want %q", got, "john")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveLinkedPeerID_NoMatch(t *testing.T) {
|
||||
links := map[string][]string{
|
||||
"john": {"telegram:123"},
|
||||
}
|
||||
got := resolveLinkedPeerID(links, "discord", "999")
|
||||
if got != "" {
|
||||
t.Errorf("resolveLinkedPeerID no match = %q, want empty", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAgentSessionKey_Valid(t *testing.T) {
|
||||
parsed := ParseAgentSessionKey("agent:sales:telegram:direct:user123")
|
||||
if parsed == nil {
|
||||
|
||||
Reference in New Issue
Block a user