Skip to content

Commit 2944a75

Browse files
committed
dont modify cilbox
more cleanup needs cleanup still more cleanup
1 parent fea6dca commit 2944a75

240 files changed

Lines changed: 24738 additions & 974 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Basis Server/BasisNetworkCore/BasisConfigXmlDocs.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ private static void RegisterServerConfig()
205205
t.Fields.Add(new FieldDoc("VoiceChatLocked", " Drop voice (normal and shout) from peers lacking basis.voice.lockbypass. Enforced server-side, so a modified client cannot talk past it. true|false; default false. "));
206206
t.Fields.Add(new FieldDoc("MediaPlayerLocked", " Stop non-bypass clients from loading new media player URLs and from accepting inbound ones. Enforced client-side (media state rides the generic scene relay). Already-playing media keeps playing. true|false; default false. "));
207207
t.Fields.Add(new FieldDoc("CameraCaptureLocked", " Stop non-bypass clients from taking photos with the handheld camera. Enforced client-side (capture is entirely local). Separate from CameraMetadataDisallowMask, which only strips metadata. true|false; default false. "));
208+
t.Fields.Add(new FieldDoc("SafeDisplayNamesForced", " Render other players' display names with rich-text markup stripped and TMP rich text off. Enforced client-side. Stops name markup being used to draw over the screen. true|false; default false. "));
208209
t.Fields.Add(new FieldDoc("PropGrabbingLocked", " Stop non-bypass clients from picking up or grabbing props. Enforced client-side (grabbing is local interaction logic). Separate from PropsLocked, which blocks prop loading instead. true|false; default false. "));
209210
_docs[typeof(global::Configuration)] = t;
210211
}

Basis Server/BasisNetworkCore/BasisServerConfiguration.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,11 @@ public class Configuration
220220
/// *loading* rather than handling already-spawned ones. Default off.
221221
/// </summary>
222222
public bool PropGrabbingLocked = false;
223+
/// <summary>
224+
/// When true, clients render other players' display names with rich-text markup stripped and
225+
/// TMP rich text disabled on the nameplate. Enforced client-side. Default off.
226+
/// </summary>
227+
public bool SafeDisplayNamesForced = false;
223228

224229
// ── REST API ──────────────────────────────────────────────────────────────
225230
/// <summary>Set to true to enable the REST management API.</summary>
@@ -321,6 +326,16 @@ public void ProcessEnvironmentalOverrides()
321326
ApplyEnvironmentalOverridesTo(this);
322327
}
323328

329+
/// <summary>Field names whose values must never reach the log.</summary>
330+
private static bool IsSecretFieldName(string fieldName)
331+
{
332+
if (string.IsNullOrEmpty(fieldName)) return false;
333+
return fieldName.IndexOf("password", StringComparison.OrdinalIgnoreCase) >= 0
334+
|| fieldName.IndexOf("apikey", StringComparison.OrdinalIgnoreCase) >= 0
335+
|| fieldName.IndexOf("secret", StringComparison.OrdinalIgnoreCase) >= 0
336+
|| fieldName.IndexOf("token", StringComparison.OrdinalIgnoreCase) >= 0;
337+
}
338+
324339
private static void ApplyEnvironmentalOverridesTo(object target)
325340
{
326341
if (target == null) return;
@@ -338,7 +353,7 @@ private static void ApplyEnvironmentalOverridesTo(object target)
338353
string value = Environment.GetEnvironmentVariable(field.Name);
339354
if (value == null) continue;
340355

341-
BNL.Log($"Applying Environmental Override with Field:{field.Name} Value:{value}");
356+
BNL.Log($"Applying Environmental Override with Field:{field.Name} Value:{(IsSecretFieldName(field.Name) ? "<redacted>" : value)}");
342357

343358
if (field.FieldType == typeof(int))
344359
{

Basis Server/BasisNetworkCore/NetDataReader.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ public void Get(out Guid result)
224224

225225
public byte GetByte()
226226
{
227+
// _data is the pooled buffer and outlives this packet, so an unchecked read past
228+
// _dataSize returns a stale byte instead of faulting.
229+
if (_position >= _dataSize)
230+
throw new InvalidOperationException($"Not enough data to read 1 byte. Position={_position}, DataSize={_dataSize}");
227231
byte res = _data[_position];
228232
_position++;
229233
return res;

Basis Server/BasisNetworkCore/Serializable/AdminRequest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ public enum AdminRequestMode : byte
188188
// props. Enforced client-side — grabbing is local interaction logic. Separate from
189189
// GlobalToggleProps, which blocks prop loading instead.
190190
GlobalTogglePropGrabbing,
191+
192+
// admin: toggle forced safe display names. While set, clients strip rich-text markup
193+
// from other players' display names and disable TMP rich text on the nameplate.
194+
// Enforced client-side — nameplate rendering is entirely local.
195+
GlobalToggleSafeDisplayNames,
191196
}
192197
}
193198
}

Basis Server/BasisNetworkCore/Serializable/BasisMessageManifest.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@ public bool Deserialize(NetDataReader reader)
8585
return false;
8686
}
8787

88+
// Each descriptor costs at least a byte on the wire.
89+
if (count > reader.AvailableBytes)
90+
{
91+
BNL.LogError($"BasisMessageSupply: count {count} exceeds available {reader.AvailableBytes}");
92+
Descriptors = Array.Empty<BasisMessageDescriptor>();
93+
return false;
94+
}
95+
8896
Descriptors = new BasisMessageDescriptor[count];
8997
for (int i = 0; i < count; i++)
9098
{
@@ -126,6 +134,14 @@ public bool Deserialize(NetDataReader reader)
126134
return false;
127135
}
128136

137+
// Each id is 2 bytes on the wire.
138+
if (count * 2 > reader.AvailableBytes)
139+
{
140+
BNL.LogError($"BasisMessageSubscribe: count {count} exceeds available {reader.AvailableBytes}");
141+
Ids = Array.Empty<ushort>();
142+
return false;
143+
}
144+
129145
Ids = new ushort[count];
130146
for (int i = 0; i < count; i++)
131147
{

Basis Server/BasisNetworkServer/BasisNetworkMessageProcessor/BasisNetworkMessageProcessor.cs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
public static class BasisNetworkMessageProcessor
1616
{
1717
private const int MaxErrorsBeforeWarning = 50;
18+
/// <summary>Protocol errors tolerated from one peer before it is dropped.</summary>
19+
private const int MaxErrorsBeforeDisconnect = 500;
1820
private static readonly ConcurrentDictionary<int, int> _peerErrorCounts = new();
1921

2022
public static void ClearPeerErrors(int peerId) => _peerErrorCounts.TryRemove(peerId, out _);
@@ -60,12 +62,7 @@ public static void ProcessMessage(NetPeer peer, NetPacketReader reader, byte cha
6062
);
6163
}
6264
reader.Recycle();
63-
if (errorCount >= MaxErrorsBeforeWarning)
64-
{
65-
BNL.LogError($"Peer {peer.Id} has reached {errorCount} protocol errors. The server has detected an issue with this client or its connection.");
66-
BasisPlayerModeration.SendBackMessage(peer, "The server has detected an issue with your client or connection. You may experience problems.");
67-
_peerErrorCounts.TryRemove(peer.Id, out _);
68-
}
65+
HandleErrorEscalation(peer, errorCount);
6966
}
7067
}
7168

@@ -77,11 +74,25 @@ private static void HandleUnknown(NetPeer peer, NetPacketReader reader, byte cha
7774
BNL.LogError($"Unknown {kind}: {channel} ({reader.AvailableBytes} bytes remaining) from peer {peer.Id} (error #{errorCount})");
7875
}
7976
reader.Recycle();
80-
if (errorCount >= MaxErrorsBeforeWarning)
77+
HandleErrorEscalation(peer, errorCount);
78+
}
79+
80+
/// <summary>
81+
/// Warns once at the warning threshold and disconnects at the hard limit. The counter must
82+
/// not be cleared on warning, or the limit can never be exceeded.
83+
/// </summary>
84+
private static void HandleErrorEscalation(NetPeer peer, int errorCount)
85+
{
86+
if (errorCount == MaxErrorsBeforeWarning)
8187
{
8288
BNL.LogError($"Peer {peer.Id} has reached {errorCount} protocol errors. The server has detected an issue with this client or its connection.");
8389
BasisPlayerModeration.SendBackMessage(peer, "The server has detected an issue with your client or connection. You may experience problems.");
90+
}
91+
else if (errorCount >= MaxErrorsBeforeDisconnect)
92+
{
93+
BNL.LogError($"Peer {peer.Id} exceeded {MaxErrorsBeforeDisconnect} protocol errors; disconnecting.");
8494
_peerErrorCounts.TryRemove(peer.Id, out _);
95+
peer.Disconnect();
8596
}
8697
}
8798
}

Basis Server/BasisNetworkServer/BasisNetworkResourceManagement.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,18 @@ public static void UnloadResource(UnLoadResource unLoadResource, NetPeer peer)
174174
return;
175175
}
176176

177+
// Creator-or-moderator, same rule SetStatic applies. The unload permission node is in the
178+
// default group, so without this any player can delete every other player's props.
179+
bool isModeratorUnload = PermissionIntegration.HasValidRequirement(peer, PermNodes.protection);
180+
bool isCreatorUnload = NetworkServer.AuthIdentity.NetIDToUUID(peer, out string unloadRequesterUuid)
181+
&& !string.IsNullOrEmpty(resource.UUIDOfCreator)
182+
&& unloadRequesterUuid == resource.UUIDOfCreator;
183+
if (!isCreatorUnload && !isModeratorUnload)
184+
{
185+
BNL.LogError($"Peer {peer.Id} tried to unload [{unLoadResource.LoadedNetID}] they did not create.");
186+
return;
187+
}
188+
177189
// Only remove AFTER validation
178190
if (!UshortNetworkDatabase.TryRemove(unLoadResource.LoadedNetID, out _))
179191
{

Basis Server/BasisNetworkServer/BasisNetworking/BasisNetworkContentShare.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,14 @@ public static void HandleContentShareCleanup(NetPacketReader reader, NetPeer pee
140140
{
141141
return;
142142
}
143+
// ContentShareDelete is default-granted, so the sharer check is what stops one player
144+
// deleting everyone else's orbs.
145+
if (existing.playerIdMessage.playerID != (ushort)peer.Id
146+
&& !PermissionIntegration.HasValidRequirement(peer, PermNodes.protection))
147+
{
148+
BNL.LogError($"Peer {peer.Id} tried to remove content sphere {msg.SphereNetID} they did not share.");
149+
return;
150+
}
143151
if (ActiveSpheres.TryRemove(msg.SphereNetID, out _))
144152
{
145153
BNL.Log($"Content sphere removed: {msg.SphereNetID}");

Basis Server/BasisNetworkServer/BasisNetworking/BasisNetworkOwnership.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,12 @@ public static void RemoveOwnership(NetPacketReader Reader, NetPeer Peer)
5757
{
5858
if (ownershipByObjectId.TryGetValue(ownershipTransferMessage.ownershipID, out ushort PlayerId))
5959
{
60-
if (PlayerId == ownershipTransferMessage.playerIdMessage.playerID)
60+
// Authorize against the sending peer, not the id in the packet: the client
61+
// fills that field in itself, so trusting it lets any peer release any
62+
// object by naming its owner.
63+
if (PlayerId == (ushort)Peer.Id)
6164
{
65+
ownershipTransferMessage.playerIdMessage.playerID = PlayerId;
6266
if (RemoveObject(ownershipTransferMessage.ownershipID))
6367
{
6468
NetDataWriter Writer = NetworkServer.RentWriter();

Basis Server/BasisNetworkServer/BasisServerHandleEvents.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1421,7 +1421,16 @@ public static void UnloadResource(NetPacketReader Reader, NetPeer Peer)
14211421
UnLoadResource.Deserialize(Reader);
14221422
Reader.Recycle();
14231423

1424-
switch (UnLoadResource.Mode)
1424+
// Tier comes from the stored record, not the packet: Mode is client-supplied and is
1425+
// never compared against the target, so a user denied world-unload could send Mode 0
1426+
// and have the prop permission checked instead.
1427+
if (!BasisNetworkResourceManagement.UshortNetworkDatabase.TryGetValue(UnLoadResource.LoadedNetID, out LocalLoadResource TargetResource))
1428+
{
1429+
BNL.LogError($"Trying to unload an object that does not exist! ID Provided was [{UnLoadResource.LoadedNetID}]");
1430+
return;
1431+
}
1432+
1433+
switch (TargetResource.Mode)
14251434
{
14261435
case 0:
14271436
if (PermissionIntegration.HasValidRequirement(Peer, PermNodes.ResourceUnloadProp) == false)

0 commit comments

Comments
 (0)