diff --git a/src/graphics.zig b/src/graphics.zig index a72ccff4..365454b9 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -572,7 +572,7 @@ pub const TextBuffer = struct { // MARK: TextBuffer } } - const Parser = struct { + pub const Parser = struct { unicodeIterator: std.unicode.Utf8Iterator, currentFontEffect: FontEffect, parsedText: main.List(u32), @@ -664,6 +664,49 @@ pub const TextBuffer = struct { // MARK: TextBuffer } }; } + + pub fn countVisibleCharacters(text: []const u8) usize { + var unicodeIterator = std.unicode.Utf8Iterator{.bytes = text, .i = 0}; + var count: usize = 0; + var curChar = unicodeIterator.nextCodepoint() orelse return count; + while(true) switch(curChar) { + '*' => { + curChar = unicodeIterator.nextCodepoint() orelse break; + }, + '_' => { + curChar = unicodeIterator.nextCodepoint() orelse break; + if(curChar == '_') { + curChar = unicodeIterator.nextCodepoint() orelse break; + } else { + count += 1; + } + }, + '~' => { + curChar = unicodeIterator.nextCodepoint() orelse break; + if(curChar == '~') { + curChar = unicodeIterator.nextCodepoint() orelse break; + } else { + count += 1; + } + }, + '\\' => { + curChar = unicodeIterator.nextCodepoint() orelse break; + curChar = unicodeIterator.nextCodepoint() orelse break; + count += 1; + }, + '#' => { + for(0..7) |_| curChar = unicodeIterator.nextCodepoint() orelse break; + }, + 'ยง' => { + curChar = unicodeIterator.nextCodepoint() orelse break; + }, + else => { + count += 1; + curChar = unicodeIterator.nextCodepoint() orelse break; + } + }; + return count; + } }; pub fn init(allocator: NeverFailingAllocator, text: []const u8, initialFontEffect: FontEffect, showControlCharacters: bool, alignment: Alignment) TextBuffer { diff --git a/src/gui/windows/change_name.zig b/src/gui/windows/change_name.zig index f412fde8..9eb7f364 100644 --- a/src/gui/windows/change_name.zig +++ b/src/gui/windows/change_name.zig @@ -20,6 +20,10 @@ var textComponent: *TextInput = undefined; const padding: f32 = 8; fn apply(_: usize) void { + if(textComponent.currentString.items.len > 500 or main.graphics.TextBuffer.Parser.countVisibleCharacters(textComponent.currentString.items) > 50) { + std.log.err("Name is too long with {}/{} characters. Limits are 50/500", .{main.graphics.TextBuffer.Parser.countVisibleCharacters(textComponent.currentString.items), textComponent.currentString.items.len}); + return; + } const oldName = settings.playerName; main.globalAllocator.free(settings.playerName); settings.playerName = main.globalAllocator.dupe(u8, textComponent.currentString.items); diff --git a/src/gui/windows/chat.zig b/src/gui/windows/chat.zig index 6e1a4d40..e69aae67 100644 --- a/src/gui/windows/chat.zig +++ b/src/gui/windows/chat.zig @@ -139,7 +139,12 @@ pub fn addMessage(msg: []const u8) void { pub fn sendMessage(_: usize) void { if(input.currentString.items.len != 0) { - main.network.Protocols.chat.send(main.game.world.?.conn, input.currentString.items); - input.clear(); + const data = input.currentString.items; + if(data.len > 10000 or main.graphics.TextBuffer.Parser.countVisibleCharacters(data) > 1000) { + std.log.err("Chat message is too long with {}/{} characters. Limits are 1000/10000", .{main.graphics.TextBuffer.Parser.countVisibleCharacters(data), data.len}); + } else { + main.network.Protocols.chat.send(main.game.world.?.conn, data); + input.clear(); + } } } diff --git a/src/network.zig b/src/network.zig index e4eac3f4..dfc6c3b2 100644 --- a/src/network.zig +++ b/src/network.zig @@ -654,6 +654,10 @@ pub const Protocols = struct { const zon = ZonElement.parseFromString(main.stackAllocator, data[1..]); defer zon.deinit(main.stackAllocator); const name = zon.get([]const u8, "name", "unnamed"); + if(name.len > 500 or main.graphics.TextBuffer.Parser.countVisibleCharacters(name) > 50) { + std.log.err("Player has too long name with {}/{} characters.", .{main.graphics.TextBuffer.Parser.countVisibleCharacters(name), name.len}); + return error.Invalid; + } const version = zon.get([]const u8, "version", "unknown"); std.log.info("User {s} joined using version {s}.", .{name, version}); @@ -1081,6 +1085,10 @@ pub const Protocols = struct { pub const asynchronous = false; fn receive(conn: *Connection, data: []const u8) !void { if(conn.user) |user| { + if(data.len > 10000 or main.graphics.TextBuffer.Parser.countVisibleCharacters(data) > 1000) { + std.log.err("Received too long chat message with {}/{} characters.", .{main.graphics.TextBuffer.Parser.countVisibleCharacters(data), data.len}); + return error.Invalid; + } main.server.messageFrom(data, user); } else { main.gui.windowlist.chat.addMessage(data);