Search Apps Documentation Source Content File Folder Download Copy Actions Download

nightsky_test.gno

6.87 Kb · 205 lines
  1package nightsky
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nt/avl/v0"
  7	"gno.land/p/nt/testutils/v0"
  8	"gno.land/p/nt/uassert/v0"
  9	"gno.land/p/nt/urequire/v0"
 10	nightsky "gno.land/p/nym-vikbez000/nightsky0"
 11)
 12
 13const scopeA = "gno.land/r/test/scopea"
 14
 15func reset() {
 16	telescopes = avl.NewTree()
 17	recentCaptures = nightsky.NewCaptureFeed(maxRecentCaptures)
 18}
 19
 20func cfg(name, owner string) nightsky.TelescopeConfig {
 21	return nightsky.NewTelescopeConfig(name, "Seestar S50", 1, 2, owner, "")
 22}
 23
 24// registerAs simulates a telescope code realm at pkgPath crossing into the
 25// registry to register itself.
 26func registerAs(cur realm, pkgPath string, c nightsky.TelescopeConfig) {
 27	testing.SetRealm(testing.NewCodeRealm(pkgPath))
 28	Register(cross(cur), c)
 29}
 30
 31func TestRegisterAndDedup(cur realm, t *testing.T) {
 32	reset()
 33
 34	registerAs(cur, scopeA, cfg("Scope A", "g1owner"))
 35	urequire.Equal(t, 1, GetTelescopeCount())
 36
 37	// RealmPath is stamped from the caller's pkgPath, not the (empty) input.
 38	stored, ok := telescopes.Get(scopeA)
 39	urequire.True(t, ok)
 40	uassert.Equal(t, scopeA, stored.(nightsky.TelescopeConfig).RealmPath)
 41
 42	// Duplicate registration from the same realm is ignored.
 43	registerAs(cur, scopeA, cfg("Scope A", "g1owner"))
 44	uassert.Equal(t, 1, GetTelescopeCount())
 45
 46	// A second telescope from a different realm is added.
 47	registerAs(cur, "gno.land/r/test/scopeb", cfg("Scope B", "g1owner2"))
 48	uassert.Equal(t, 2, GetTelescopeCount())
 49}
 50
 51func TestRegisterRejectsUserCall(cur realm, t *testing.T) {
 52	reset()
 53
 54	// A direct user transaction (no intermediary realm) must be rejected.
 55	testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("eoa")))
 56	uassert.AbortsContains(t, cur, "realm code", func() {
 57		Register(cross(cur), cfg("Bad", "g1owner"))
 58	})
 59	uassert.Equal(t, 0, GetTelescopeCount())
 60}
 61
 62func TestOnlineCountAndStatus(cur realm, t *testing.T) {
 63	reset()
 64
 65	c := cfg("Scope A", "g1owner")
 66	c.UpdateStatus("online")
 67	registerAs(cur, scopeA, c)
 68	uassert.Equal(t, 1, GetOnlineTelescopeCount())
 69
 70	// The telescope realm updates its status to offline.
 71	testing.SetRealm(testing.NewCodeRealm(scopeA))
 72	UpdateTelescopeStatus(cross(cur), "offline")
 73	uassert.Equal(t, 0, GetOnlineTelescopeCount())
 74	uassert.Equal(t, 1, GetTelescopeCount())
 75}
 76
 77func TestSubmitCaptureFeed(cur realm, t *testing.T) {
 78	reset()
 79	registerAs(cur, scopeA, cfg("Scope A", "g1owner"))
 80
 81	testing.SetRealm(testing.NewCodeRealm(scopeA))
 82	SubmitCapture(cross(cur), "https://img/1.png", 5, 10, 30, "g1owner")
 83	SubmitCapture(cross(cur), "https://img/2.png", 6, 11, 40, "g1owner")
 84
 85	latest, ok := recentCaptures.Latest()
 86	urequire.True(t, ok)
 87	uassert.Equal(t, "https://img/2.png", latest.ImageURL)
 88	uassert.Equal(t, 2, recentCaptures.Len())
 89}
 90
 91func TestAdminRemoveAndAuth(cur realm, t *testing.T) {
 92	reset()
 93	registerAs(cur, scopeA, cfg("Scope A", "g1owner"))
 94	urequire.Equal(t, 1, GetTelescopeCount())
 95
 96	// Non-admin cannot remove.
 97	testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("intruder")))
 98	uassert.AbortsContains(t, cur, "not owner", func() {
 99		RemoveTelescope(cross(cur), scopeA)
100	})
101	uassert.Equal(t, 1, GetTelescopeCount())
102
103	// Admin can remove.
104	testing.SetRealm(testing.NewUserRealm(OwnableMain.Owner()))
105	RemoveTelescope(cross(cur), scopeA)
106	uassert.Equal(t, 0, GetTelescopeCount())
107
108	// Removing a missing telescope aborts.
109	uassert.AbortsContains(t, cur, "not found", func() {
110		RemoveTelescope(cross(cur), scopeA)
111	})
112}
113
114// --- Adversarial ("steal a telescope") tests -------------------------------
115// An attacker realm or EOA tries to hijack, impersonate, or wipe telescopes
116// that are not theirs.
117
118const (
119	victimPath   = "gno.land/r/victim/scope"
120	attackerPath = "gno.land/r/attacker/evil"
121)
122
123// TestAttackerRealmCannotTouchVictim: registry mutations are keyed by the
124// caller's own pkgPath (cur.Previous().PkgPath()). An unregistered attacker
125// realm therefore cannot update, capture-to, or unregister a victim's entry —
126// it only ever addresses its own (nonexistent) registration.
127func TestAttackerRealmCannotTouchVictim(cur realm, t *testing.T) {
128	reset()
129	registerAs(cur, victimPath, cfg("Victim Scope", "g1victim"))
130	urequire.Equal(t, 1, GetTelescopeCount())
131
132	testing.SetRealm(testing.NewCodeRealm(attackerPath))
133	uassert.AbortsContains(t, cur, "not registered", func() {
134		UpdateTelescopeStatus(cross(cur), "error")
135	})
136	uassert.AbortsContains(t, cur, "not registered", func() {
137		SubmitCapture(cross(cur), "https://evil/forged.png", 1, 1, 10, "g1victim")
138	})
139	uassert.AbortsContains(t, cur, "not registered", func() {
140		UnregisterTelescope(cross(cur))
141	})
142
143	// Victim's entry is untouched.
144	stored, ok := telescopes.Get(victimPath)
145	urequire.True(t, ok)
146	uassert.Equal(t, "Victim Scope", stored.(nightsky.TelescopeConfig).Name)
147	uassert.Equal(t, 1, GetTelescopeCount())
148}
149
150// TestAttackerCannotUnregisterVictim: even when the attacker is itself
151// registered, UnregisterTelescope removes only the caller's own entry — it
152// cannot take down a neighbour.
153func TestAttackerCannotUnregisterVictim(cur realm, t *testing.T) {
154	reset()
155	registerAs(cur, victimPath, cfg("Victim Scope", "g1victim"))
156	registerAs(cur, attackerPath, cfg("Evil Scope", "g1attacker"))
157	urequire.Equal(t, 2, GetTelescopeCount())
158
159	testing.SetRealm(testing.NewCodeRealm(attackerPath))
160	UnregisterTelescope(cross(cur)) // removes the attacker, nothing else
161
162	uassert.False(t, telescopes.Has(attackerPath))
163	uassert.True(t, telescopes.Has(victimPath)) // victim survives
164	uassert.Equal(t, 1, GetTelescopeCount())
165}
166
167// TestAttackerCaptureCannotImpersonateVictim: the network feed stamps each
168// capture's TelescopeID from the caller's own registration, so an attacker
169// cannot make a forged image appear to come from the victim's telescope —
170// regardless of the capturedBy value they pass.
171func TestAttackerCaptureCannotImpersonateVictim(cur realm, t *testing.T) {
172	reset()
173	registerAs(cur, victimPath, cfg("Victim Scope", "g1victim"))
174	registerAs(cur, attackerPath, cfg("Evil Scope", "g1attacker"))
175
176	testing.SetRealm(testing.NewCodeRealm(attackerPath))
177	SubmitCapture(cross(cur), "https://evil/forged.png", 1, 1, 10, "g1victim")
178
179	latest, ok := recentCaptures.Latest()
180	urequire.True(t, ok)
181	uassert.Equal(t, "Evil Scope", latest.TelescopeID) // not "Victim Scope"
182}
183
184// TestNonAdminCannotUseAdminPowers: the network-admin functions reject anyone
185// who is not the ownable owner, so an intruder cannot wipe the registry or the
186// capture feed.
187func TestNonAdminCannotUseAdminPowers(cur realm, t *testing.T) {
188	reset()
189	registerAs(cur, victimPath, cfg("Victim Scope", "g1victim"))
190	urequire.Equal(t, 1, GetTelescopeCount())
191
192	testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("intruder")))
193	uassert.AbortsContains(t, cur, "not owner", func() {
194		RemoveTelescope(cross(cur), victimPath)
195	})
196	uassert.AbortsContains(t, cur, "not owner", func() {
197		ClearAllTelescopes(cross(cur))
198	})
199	uassert.AbortsContains(t, cur, "not owner", func() {
200		RemoveCapture(cross(cur), 0)
201	})
202
203	// Nothing was removed.
204	uassert.Equal(t, 1, GetTelescopeCount())
205}