diff --git a/server/src/lib/validators.test.ts b/server/src/lib/validators.test.ts index faaae3b..86113b4 100644 --- a/server/src/lib/validators.test.ts +++ b/server/src/lib/validators.test.ts @@ -360,3 +360,54 @@ describe('attack inputs', () => { expect(httpUrlSchema.safeParse('data:text/html,

hi

').success).toBe(false) }) }) + +describe('auth & registration edge cases', () => { + it('unicode bot name rejected', () => { + expect(botNameSchema.safeParse('ビットコイン').success).toBe(false) + expect(botNameSchema.safeParse('café').success).toBe(false) + expect(botNameSchema.safeParse('bot🚀').success).toBe(false) + expect(botNameSchema.safeParse('böt').success).toBe(false) + }) + + it('bot name with spaces rejected', () => { + expect(botNameSchema.safeParse('my bot').success).toBe(false) + }) + + it('bot name with special chars rejected', () => { + expect(botNameSchema.safeParse('bot!@#').success).toBe(false) + expect(botNameSchema.safeParse('bot.name').success).toBe(false) + expect(botNameSchema.safeParse('bot/name').success).toBe(false) + }) + + it('valid bot names accepted', () => { + expect(botNameSchema.safeParse('SatoshiBot').success).toBe(true) + expect(botNameSchema.safeParse('bot-1').success).toBe(true) + expect(botNameSchema.safeParse('bot_2').success).toBe(true) + expect(botNameSchema.safeParse('A1').success).toBe(true) + }) + + it('two bots with same webhook URL: both pass validation (uniqueness enforced at DB level)', () => { + const pub1 = 'a'.repeat(64) + const pub2 = 'b'.repeat(64) + const sharedUrl = 'https://example.com/webhook' + const r1 = registerSchema.safeParse({ pubkey: pub1, name: 'Bot1', webhookUrl: sharedUrl }) + const r2 = registerSchema.safeParse({ pubkey: pub2, name: 'Bot2', webhookUrl: sharedUrl }) + expect(r1.success).toBe(true) + expect(r2.success).toBe(true) + // Note: same webhook URL is allowed — uniqueness is on name, not URL + }) + + it('pubkey must be exactly 64 hex chars', () => { + expect(pubkeySchema.safeParse('a'.repeat(63)).success).toBe(false) // too short + expect(pubkeySchema.safeParse('a'.repeat(65)).success).toBe(false) // too long + expect(pubkeySchema.safeParse('g'.repeat(64)).success).toBe(false) // non-hex + expect(pubkeySchema.safeParse('A'.repeat(64)).success).toBe(false) // uppercase (not lowercase hex) + expect(pubkeySchema.safeParse('a'.repeat(64)).success).toBe(true) // valid + }) + + it('register rejects missing required fields', () => { + expect(registerSchema.safeParse({}).success).toBe(false) + expect(registerSchema.safeParse({ pubkey: 'a'.repeat(64) }).success).toBe(false) // missing name + expect(registerSchema.safeParse({ name: 'Bot1' }).success).toBe(false) // missing pubkey + }) +})