import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; /** HTTP endpoint documented by 0098sms.com for sending via query string. */ const SMS_0098_SEND_URL = 'http://www.0098sms.com/sendsmslink.aspx'; @Injectable() export class SmsService { private readonly logger = new Logger(SmsService.name); constructor(private readonly config: ConfigService) {} /** True when username, password, and sender line are all set. */ isConfigured(): boolean { const username = this.config.get('SMS_USERNAME'); const password = this.getPassword(); const sender = this.config.get('SMS_SENDER'); return Boolean(username && password && sender); } /** * Formats mobile for 0098 `TO` (Iranian mobiles as 09xxxxxxxxx). */ normalizePhoneForSms(mobile: string): string { const digits = String(mobile ?? '').replace(/\D/g, ''); if (digits.startsWith('98') && digits.length === 12) { return `0${digits.slice(2)}`; } if (digits.startsWith('0') && digits.length === 11) { return digits; } if (digits.length === 10 && digits.startsWith('9')) { return `0${digits}`; } return digits; } async sendOtpSms(mobile: string, code: string): Promise { const text = `کد ورود شما: ${code}`; return this.sendSms(mobile, text); } async sendSms(phone: string, text: string): Promise { const username = this.config.get('SMS_USERNAME'); const password = this.getPassword(); const sender = this.config.get('SMS_SENDER'); const domain = this.config.get('SMS_DOMAIN') ?? '0098'; if (!username || !password || !sender) { return false; } const params = new URLSearchParams({ FROM: sender, TO: this.normalizePhoneForSms(phone), TEXT: text, USERNAME: username, PASSWORD: password, DOMAIN: domain, }); const url = `${SMS_0098_SEND_URL}?${params.toString()}`; try { const res = await fetch(url); const body = await res.text(); if (!res.ok) { this.logger.warn( `SMS HTTP ${res.status}: ${body.slice(0, 300)}`, ); return false; } return true; } catch (e) { this.logger.error( '[SMS] request failed', e instanceof Error ? e.stack : e, ); return false; } } private getPassword(): string | undefined { return ( this.config.get('SMS_PASSWORD') ?? this.config.get('SMS_API_KEY') ); } }