Hosted rooms' instance IDs start with their owner's IMVU account now, so the client asks about their products as the owner itself, and the mapping from 2100000000 is never used. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
2df46da3ad
commit
56c47e806f
6 files changed
+5
-78
No files matched your search
@@ -156,7 +156,6 @@ func run(logger *log.Logger, listen, ready string, parentPID int, trace bool, pa
|
|||||||
if prods != nil {
|
if prods != nil {
|
||||||
prods.Hosted = rooms
|
prods.Hosted = rooms
|
||||||
rooms.User, rooms.LocalProduct, rooms.GlobalProduct = prods.User, prods.LocalID, prods.ProductID
|
rooms.User, rooms.LocalProduct, rooms.GlobalProduct = prods.User, prods.LocalID, prods.ProductID
|
||||||
prods.HostedOwner = rooms.Owner
|
|
||||||
rooms.UserDeliver = prods.DeliverToUser
|
rooms.UserDeliver = prods.DeliverToUser
|
||||||
rooms.Deliver = func(c *proxy.IMQConn, m imq.Delivered) {
|
rooms.Deliver = func(c *proxy.IMQConn, m imq.Delivered) {
|
||||||
m.Message = prods.Incoming(c, m)
|
m.Message = prods.Incoming(c, m)
|
||||||
|
|||||||
@@ -645,17 +645,6 @@ func (r *Rooms) getRoom(ctx context.Context, n int64) (*Room, [][3]any, string,
|
|||||||
return &out.Room, out.Scene.Contents, out.Scene.Hash, nil
|
return &out.Room, out.Scene.Contents, out.Scene.Hash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Owner is the IMVU account owning the hosted room the client joined last (0 if none, or not known): the client
|
|
||||||
// checks the room's products against it (products.HostedOwner).
|
|
||||||
func (r *Rooms) Owner() int64 {
|
|
||||||
r.mu.Lock()
|
|
||||||
defer r.mu.Unlock()
|
|
||||||
if _, in := r.rooms[r.last]; !in {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return r.owners[r.last]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Rooms) roomCard(ctx context.Context, n int64) *http.Response {
|
func (r *Rooms) roomCard(ctx context.Context, n int64) *http.Response {
|
||||||
rm, _, _, err := r.getRoom(ctx, n)
|
rm, _, _, err := r.getRoom(ctx, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ func roomOwner(instance string) int64 {
|
|||||||
func isHostedInstance(instance string) bool {
|
func isHostedInstance(instance string) bool {
|
||||||
_, number, ok := strings.Cut(instance, "-")
|
_, number, ok := strings.Cut(instance, "-")
|
||||||
n, err := strconv.ParseInt(number, 10, 64)
|
n, err := strconv.ParseInt(number, 10, 64)
|
||||||
return ok && err == nil && n > HostedOwnerID // hosted rooms' numbers start above 2100000000
|
return ok && err == nil && n > hostedBase
|
||||||
}
|
}
|
||||||
|
|
||||||
// decorFetch gets a room's decorations, from memory or the hub.
|
// decorFetch gets a room's decorations, from memory or the hub.
|
||||||
|
|||||||
@@ -367,13 +367,6 @@ func (p *Products) authorizeProducts2(x *proxy.Exchange, call *xmlrpc.Call) erro
|
|||||||
type auth struct {
|
type auth struct {
|
||||||
user, product int64
|
user, product int64
|
||||||
}
|
}
|
||||||
// In a room hosted by T5DE's hub, the client asks about the room's products as user 2100000000 (the first part
|
|
||||||
// of the room's ID): IMVU is asked about the room owner's instead, and answers go back as 2100000000.
|
|
||||||
owner := int64(0)
|
|
||||||
if p.HostedOwner != nil {
|
|
||||||
owner = p.HostedOwner()
|
|
||||||
}
|
|
||||||
hostedAsked := map[int64]bool{}
|
|
||||||
var community []auth
|
var community []auth
|
||||||
forward := []xmlrpc.Value{table[0]}
|
forward := []xmlrpc.Value{table[0]}
|
||||||
asked := map[auth]bool{}
|
asked := map[auth]bool{}
|
||||||
@@ -387,10 +380,6 @@ func (p *Products) authorizeProducts2(x *proxy.Exchange, call *xmlrpc.Call) erro
|
|||||||
if !ok1 || !ok2 {
|
if !ok1 || !ok2 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if user == HostedOwnerID && owner > 0 {
|
|
||||||
user, hostedAsked[product] = owner, true
|
|
||||||
row = []xmlrpc.Value{user, product}
|
|
||||||
}
|
|
||||||
if !IsCommunity(product) {
|
if !IsCommunity(product) {
|
||||||
if !asked[auth{user, product}] {
|
if !asked[auth{user, product}] {
|
||||||
forward, asked[auth{user, product}] = append(forward, row), true
|
forward, asked[auth{user, product}] = append(forward, row), true
|
||||||
@@ -405,33 +394,9 @@ func (p *Products) authorizeProducts2(x *proxy.Exchange, call *xmlrpc.Call) erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(community) == 0 && len(hostedAsked) == 0 {
|
if len(community) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// hostedBack gives rows asked about as 2100000000 that user ID back.
|
|
||||||
hostedBack := func(columns []xmlrpc.Value, rows []xmlrpc.Value) {
|
|
||||||
userCol, productCol := -1, -1
|
|
||||||
for i, c := range columns {
|
|
||||||
switch c {
|
|
||||||
case "userId":
|
|
||||||
userCol = i
|
|
||||||
case "productId":
|
|
||||||
productCol = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if userCol < 0 || productCol < 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, row := range rows {
|
|
||||||
r, ok := row.([]xmlrpc.Value)
|
|
||||||
if !ok || len(r) <= userCol || len(r) <= productCol {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if product, _ := r[productCol].(int64); r[userCol] == owner && hostedAsked[product] {
|
|
||||||
r[userCol] = int64(HostedOwnerID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ours := func(columns []xmlrpc.Value) []xmlrpc.Value {
|
ours := func(columns []xmlrpc.Value) []xmlrpc.Value {
|
||||||
var rows []xmlrpc.Value
|
var rows []xmlrpc.Value
|
||||||
for _, a := range community {
|
for _, a := range community {
|
||||||
@@ -464,7 +429,6 @@ func (p *Products) authorizeProducts2(x *proxy.Exchange, call *xmlrpc.Call) erro
|
|||||||
columns[i] = c
|
columns[i] = c
|
||||||
}
|
}
|
||||||
out := append([]xmlrpc.Value{columns}, ours(columns)...)
|
out := append([]xmlrpc.Value{columns}, ours(columns)...)
|
||||||
hostedBack(columns, out[1:])
|
|
||||||
x.Response = localResponse(200, "text/xml", (&xmlrpc.Response{Params: []xmlrpc.Value{out}}).Marshal())
|
x.Response = localResponse(200, "text/xml", (&xmlrpc.Response{Params: []xmlrpc.Value{out}}).Marshal())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -492,7 +456,6 @@ func (p *Products) authorizeProducts2(x *proxy.Exchange, call *xmlrpc.Call) erro
|
|||||||
return body, errors.New("products: unexpected authorizeProducts2 columns")
|
return body, errors.New("products: unexpected authorizeProducts2 columns")
|
||||||
}
|
}
|
||||||
all := append(rows, ours(columns)...)
|
all := append(rows, ours(columns)...)
|
||||||
hostedBack(columns, all[1:])
|
|
||||||
r.Params[0] = all
|
r.Params[0] = all
|
||||||
return r.Marshal(), nil
|
return r.Marshal(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,10 +73,8 @@ type Products struct {
|
|||||||
SaveDecorations func(ctx context.Context, instance string, items []DecorItem) error
|
SaveDecorations func(ctx context.Context, instance string, items []DecorItem) error
|
||||||
decor decorations
|
decor decorations
|
||||||
|
|
||||||
// Hosted, if set, serves T5DE-hosted rooms' queues (the hosted package); HostedOwner is the IMVU account owning
|
// Hosted, if set, serves T5DE-hosted rooms' queues (the hosted package).
|
||||||
// the hosted room the client is in (0 if none), whose products the room's are.
|
|
||||||
Hosted HostedRooms
|
Hosted HostedRooms
|
||||||
HostedOwner func() int64
|
|
||||||
|
|
||||||
roomMu sync.Mutex
|
roomMu sync.Mutex
|
||||||
room room
|
room room
|
||||||
@@ -110,9 +108,8 @@ func (p *Products) Ready(id string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HostedOwnerID is the user ID the client gives hosted rooms' owner: the first part of their instance IDs
|
// hostedBase is where hosted rooms' numbers start (above it; hosted.Base).
|
||||||
// (hosted.Base).
|
const hostedBase = 2100000000
|
||||||
const HostedOwnerID = 2100000000
|
|
||||||
|
|
||||||
// HostedRooms serves T5DE-hosted rooms' IMQ queues: Route answers subscriptions to them, Send takes the client's
|
// HostedRooms serves T5DE-hosted rooms' IMQ queues: Route answers subscriptions to them, Send takes the client's
|
||||||
// messages to them (message as for others, original as the client sent it, for the echo; keep: nothing to send
|
// messages to them (message as for others, original as the client sent it, for the echo; keep: nothing to send
|
||||||
|
|||||||
@@ -425,24 +425,3 @@ func TestSavedOutfits(t *testing.T) {
|
|||||||
t.Fatalf("outfits %s", body)
|
t.Fatalf("outfits %s", body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHostedRoomProducts(t *testing.T) {
|
|
||||||
h, _ := newHarness(t)
|
|
||||||
h.do("POST", "https://secure.imvu.com/api/xmlrpc/client.php", call("test.avatarInfoForLogin2"), false, false)
|
|
||||||
h.p.HostedOwner = func() int64 { return 7 } // the fake IMVU answers as user 7
|
|
||||||
auths := xmlrpc.Struct{{Name: "auths", Value: []xmlrpc.Value{
|
|
||||||
[]xmlrpc.Value{"userId", "productId"}, []xmlrpc.Value{int64(HostedOwnerID), int64(500)}}}}
|
|
||||||
_, body := h.do("POST", "http://client-dynamic.imvu.com/api/xmlrpc/client.php", call("test.authorizeProducts2", auths), true, false)
|
|
||||||
asked := h.imvu.asked["test.authorizeProducts2"]
|
|
||||||
if len(asked) != 1 || strings.Contains(asked[0], "2100000000") {
|
|
||||||
t.Fatalf("IMVU was asked %q", asked)
|
|
||||||
}
|
|
||||||
r, err := xmlrpc.ParseResponse(body)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
rows := r.Params[0].([]xmlrpc.Value)
|
|
||||||
if first := rows[1].([]xmlrpc.Value); first[0] != int64(HostedOwnerID) || first[2] != int64(500) {
|
|
||||||
t.Fatalf("answer %v", rows)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user