diff --git a/scripts/test-sms.mjs b/scripts/test-sms.mjs index a4ebfe9..f2946d4 100644 --- a/scripts/test-sms.mjs +++ b/scripts/test-sms.mjs @@ -51,9 +51,12 @@ for (const mobile of targets) { const body = await res.text(); const match = body.match(/]*>([^<]*)<\/SendSMSResult>/i); const code = match?.[1]?.trim() ?? '?'; + const n = Number(code); + const ok = Number.isFinite(n) ? n >= 0 : false; + const status = ok ? 'OK (accepted by 0098)' : 'FAILED'; - console.log(`mobile=${mobile} http=${res.status} RESULT=${code}`); - if (code !== '0') { + console.log(`mobile=${mobile} http=${res.status} RESULT=${code} ${status}`); + if (!ok) { console.log(body.slice(0, 400)); } } diff --git a/src/modules/auth/sms.service.ts b/src/modules/auth/sms.service.ts index 7114279..fbfab56 100644 --- a/src/modules/auth/sms.service.ts +++ b/src/modules/auth/sms.service.ts @@ -7,20 +7,9 @@ const SMS_0098_LINK_URL = 'http://www.0098sms.com/sendsmslink.aspx'; /** Official 0098 SOAP API (works when link endpoint is down). */ const SMS_0098_SOAP_URL = 'https://webservice.0098sms.com/service.asmx'; -const SMS_0098_ERROR_CODES: Record = { - '1': 'invalid phone number', - '2': 'no phone number', - '3': 'no sender', - '4': 'no text', - '5': 'no username', - '6': 'no password', - '7': 'no domain', - '8': 'invalid license', - '9': 'insufficient SMS credit', - '10': 'no link for this number', - '11': 'no license for link access', - '12': 'wrong username or password', - '13': 'invalid characters in message text', +/** SOAP SendSMSResult: 0 or positive = accepted (often SMS part count); negative = error. */ +const SMS_0098_SOAP_ERROR_CODES: Record = { + '-22': 'invalid mobile number format', }; export type SmsSendResult = { @@ -142,12 +131,12 @@ export class SmsService { } const code = this.parseSoapResultCode(body); - if (code === '0') { + if (this.is0098SoapSuccess(code)) { return { ok: true, transport: 'soap' }; } const reason = - SMS_0098_ERROR_CODES[code ?? ''] ?? + SMS_0098_SOAP_ERROR_CODES[code ?? ''] ?? (code ? `provider code ${code}` : 'unknown SOAP response'); this.logger.warn( `SOAP rejected to=${this.maskPhone(to)} code=${code ?? '?'} body=${body.slice(0, 200)}`, @@ -208,6 +197,17 @@ export class SmsService { } } + private is0098SoapSuccess(code: string | null): boolean { + if (code == null || code === '') { + return false; + } + const n = Number(code); + if (Number.isFinite(n)) { + return n >= 0; + } + return false; + } + private parseSoapResultCode(xml: string): string | null { const match = xml.match(/]*>([^<]*)<\/SendSMSResult>/i) ?? @@ -234,8 +234,8 @@ export class SmsService { return false; } const code = body.trim(); - if (/^\d+$/.test(code) && code !== '0') { - return false; + if (/^-?\d+$/.test(code)) { + return Number(code) >= 0; } return true; }