1
0
forked from baron/baron-sso
Files
baron-sso/backend/internal/service/sms_service.go

113 lines
3.0 KiB
Go

package service
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"strings"
"time"
"baron-sso-backend/internal/domain"
)
type SmsServiceImpl struct {
accessKey string
secretKey string
serviceID string
senderPhone string
}
func NewSmsService() domain.SmsService {
// Sanitize sender phone number right after reading from env
rawSenderPhone := os.Getenv("NAVER_SENDER_PHONE_NUMBER")
sanitizedSenderPhone := strings.ReplaceAll(rawSenderPhone, "-", "")
log.Printf("[서비스 초기화] 발신자 번호 처리: 원본='%s', 정제 후='%s'", rawSenderPhone, sanitizedSenderPhone)
return &SmsServiceImpl{
accessKey: os.Getenv("NAVER_CLOUD_ACCESS_KEY"),
secretKey: os.Getenv("NAVER_CLOUD_SECRET_KEY"),
serviceID: os.Getenv("NAVER_CLOUD_SERVICE_ID"),
senderPhone: sanitizedSenderPhone,
}
}
func (s *SmsServiceImpl) SendSms(to, content string) error {
timestamp := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)
apiURL := fmt.Sprintf("https://sens.apigw.ntruss.com/sms/v2/services/%s/messages", s.serviceID)
log.Printf("Requesting SENS API URL: %s", apiURL)
reqBody := domain.NaverSmsRequest{
Type: "SMS",
ContentType: "COMM",
CountryCode: "82",
From: s.senderPhone,
Content: content,
Messages: []domain.SmsMessage{
{
To: to,
},
},
}
jsonBody, err := json.Marshal(reqBody)
if err != nil {
return fmt.Errorf("error marshalling request body: %w", err)
}
signature, err := s.makeSignature("POST", fmt.Sprintf("/sms/v2/services/%s/messages", s.serviceID), timestamp)
if err != nil {
return fmt.Errorf("error creating signature: %w", err)
}
req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonBody))
if err != nil {
return fmt.Errorf("error creating request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-ncp-apigw-timestamp", timestamp)
req.Header.Set("x-ncp-iam-access-key", s.accessKey)
req.Header.Set("x-ncp-apigw-signature-v2", signature)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("error sending request: %w", err)
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("error reading response body: %w", err)
}
if resp.StatusCode >= 300 {
log.Printf("error response from naver cloud sms api: %s", string(respBody))
return fmt.Errorf("error sending sms: status code %d", resp.StatusCode)
}
log.Printf("sms sent successfully: %s", string(respBody))
return nil
}
func (s *SmsServiceImpl) makeSignature(method, url, timestamp string) (string, error) {
space := " "
newLine := "\n"
message := method + space + url + newLine + timestamp + newLine + s.accessKey
h := hmac.New(sha256.New, []byte(s.secretKey))
_, err := h.Write([]byte(message))
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
}