You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
53 lines
2.2 KiB
TypeScript
53 lines
2.2 KiB
TypeScript
// apps/hq/test/sms-gateway.test.ts — D28: parse the SMS gateway's balance response.
|
|
import { describe, it, expect } from 'vitest'
|
|
import { parseBalanceResponse, balanceUrl, assertSafeGatewayUrl } from '../src/sms-gateway'
|
|
|
|
describe('parseBalanceResponse (D28)', () => {
|
|
it('reads the balance from a success line (code|STATUS|balance)', () => {
|
|
const r = parseBalanceResponse('001|SUCCESS|8200')
|
|
expect(r.ok).toBe(true)
|
|
expect(r.balance).toBe(8200)
|
|
})
|
|
|
|
it('tolerates commas/spaces and a plain-number body', () => {
|
|
expect(parseBalanceResponse('000|OK|1,25,000').balance).toBe(125000)
|
|
expect(parseBalanceResponse('8200').balance).toBe(8200)
|
|
})
|
|
|
|
it('flags the real error response as failed with its message', () => {
|
|
const r = parseBalanceResponse('002|ERROR|Invalid User Id / Password')
|
|
expect(r.ok).toBe(false)
|
|
expect(r.balance).toBeNull()
|
|
expect(r.message).toMatch(/Invalid User Id/)
|
|
})
|
|
|
|
it('fails cleanly on empty or unreadable text (never a wrong number)', () => {
|
|
expect(parseBalanceResponse('').ok).toBe(false)
|
|
expect(parseBalanceResponse('welcome to the panel').ok).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('balanceUrl (D28)', () => {
|
|
it('substitutes credentials into the configured base URL', () => {
|
|
const u = balanceUrl('http://164.52.195.161/API/BalAlert.aspx', 'bankuser', 'p@ss w/special')
|
|
expect(u).toContain('uname=bankuser')
|
|
expect(u).toContain('pass=p%40ss+w%2Fspecial') // URL-encoded
|
|
})
|
|
})
|
|
|
|
describe('assertSafeGatewayUrl (D28 SSRF guard)', () => {
|
|
it('allows the vendor panel and other public hosts', () => {
|
|
expect(() => assertSafeGatewayUrl('http://164.52.195.161/API/BalAlert.aspx')).not.toThrow()
|
|
expect(() => assertSafeGatewayUrl('https://sms.vendor.example/bal')).not.toThrow()
|
|
})
|
|
it('blocks loopback, link-local metadata, and private ranges', () => {
|
|
for (const bad of [
|
|
'http://127.0.0.1/x', 'http://localhost/x', 'http://169.254.169.254/latest/meta-data',
|
|
'http://10.0.0.5/x', 'http://192.168.1.5/x', 'http://172.16.0.1/x', 'http://[::1]/x',
|
|
'http://box.internal/x', 'ftp://164.52.195.161/x',
|
|
]) {
|
|
expect(() => assertSafeGatewayUrl(bad), bad).toThrow()
|
|
}
|
|
})
|
|
})
|