File

spec/net_stun_spec.lua @ 13633:6b84d11aa09b

mod_storage_sql: Detect SQLite3 without UPSERT (or SQLCipher 3.x) SQLCipher v3.4.1 (the version in Debian 12) is based on SQLite3 v3.15.2, while UPSERT support was introduced in SQLite3 v3.24.0 This check was not needed before because we v3.24.0 has not been in a version of Debian we support for a long, long time. Note however that SQLCipher databases are not compatible across major versions, upgrading from v3.x to v4.x requires executing a migration. Attempts at making `prosodyctl mod_storage_sql upgrade` perform such a migration has not been successful. Executing the following in the `sqlcipher` tool should do the migration: PRAGMA key = '<key material>'; PRAGMA cipher_migrate;
author Kim Alvefur <zash@zash.se>
date Thu, 23 Jan 2025 19:33:05 +0100
parent 12363:0576d7d625a0
line wrap: on
line source

local hex = require "util.hex";

local function parse(pkt_desc)
	local result = {};
	for line in pkt_desc:gmatch("([^\n]+)\n") do
		local b1, b2, b3, b4 = line:match("^%s*(%x%x) (%x%x) (%x%x) (%x%x)%s");
		if b1 then
			table.insert(result, b1);
			table.insert(result, b2);
			table.insert(result, b3);
			table.insert(result, b4);
		end
	end
	return hex.decode(table.concat(result));
end

local sample_packet = parse[[
      00 01 00 60     Request type and message length
      21 12 a4 42     Magic cookie
      78 ad 34 33  }
      c6 ad 72 c0  }  Transaction ID
      29 da 41 2e  }
      00 06 00 12     USERNAME attribute header
      e3 83 9e e3  }
      83 88 e3 83  }
      aa e3 83 83  }  Username value (18 bytes) and padding (2 bytes)
      e3 82 af e3  }
      82 b9 00 00  }
      00 15 00 1c     NONCE attribute header
      66 2f 2f 34  }
      39 39 6b 39  }
      35 34 64 36  }
      4f 4c 33 34  }  Nonce value
      6f 4c 39 46  }
      53 54 76 79  }
      36 34 73 41  }
      00 14 00 0b     REALM attribute header
      65 78 61 6d  }
      70 6c 65 2e  }  Realm value (11 bytes) and padding (1 byte)
      6f 72 67 00  }
      00 08 00 14     MESSAGE-INTEGRITY attribute header
      f6 70 24 65  }
      6d d6 4a 3e  }
      02 b8 e0 71  }  HMAC-SHA1 fingerprint
      2e 85 c9 a2  }
      8c a8 96 66  }
]];

describe("net.stun", function ()
	local stun = require "net.stun";

	it("works", function ()
		local packet = stun.new_packet();
		assert.is_string(packet:serialize());
	end);

	it("can decode the sample packet", function ()
		local packet = stun.new_packet():deserialize(sample_packet);
		assert(packet);
		local method, method_name = packet:get_method();
		assert.equal(1, method);
		assert.equal("binding", method_name);
		assert.equal("example.org", packet:get_attribute("realm"));
	end);

	it("can generate the sample packet", function ()
		-- These values, and the sample packet, come from RFC 5769 2.4
		local username = string.char(
			-- U+30DE KATAKANA LETTER MA
			0xE3, 0x83, 0x9E,
			-- U+30C8 KATAKANA LETTER TO
			0xE3, 0x83, 0x88,
			-- U+30EA KATAKANA LETTER RI
			0xE3, 0x83, 0xAA,
			-- U+30C3 KATAKANA LETTER SMALL TU
			0xE3, 0x83, 0x83,
			-- U+30AF KATAKANA LETTER KU
			0xE3, 0x82, 0xAF,
			-- U+30B9 KATAKANA LETTER SU
			0xE3, 0x82, 0xB9
		);

		--    Password:  "The<U+00AD>M<U+00AA>tr<U+2168>" and "TheMatrIX" (without
		--       quotes) respectively before and after SASLprep processing
		local password = "TheMatrIX";
		local realm = "example.org";

		local p3 = stun.new_packet("binding", "request");
		p3.transaction_id = hex.decode("78AD3433C6AD72C029DA412E");
		p3:add_attribute("username", username);
		p3:add_attribute("nonce", "f//499k954d6OL34oL9FSTvy64sA");
		p3:add_attribute("realm", realm);
		local key = stun.get_long_term_auth_key(realm, username, password);
		p3:add_message_integrity(key);
		assert.equal(sample_packet, p3:serialize());
	end);
end);