118 lines
3.1 KiB
Go
118 lines
3.1 KiB
Go
package sms
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/utils"
|
|
dysms "github.com/alibabacloud-go/dysmsapi-20170525/v5/client"
|
|
"github.com/alibabacloud-go/tea/dara"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type AliyunConfig struct {
|
|
AccessKeyID string
|
|
AccessKeySecret string
|
|
Endpoint string
|
|
SignName string
|
|
LoginTemplateCode string
|
|
}
|
|
|
|
type AliyunProvider struct {
|
|
client *dysms.Client
|
|
signName string
|
|
loginTemplateCode string
|
|
log *zap.Logger
|
|
}
|
|
|
|
func NewAliyunProvider(cfg AliyunConfig, log *zap.Logger) (*AliyunProvider, error) {
|
|
cfg.Endpoint = strings.TrimSpace(cfg.Endpoint)
|
|
if cfg.Endpoint == "" {
|
|
cfg.Endpoint = "dysmsapi.aliyuncs.com"
|
|
}
|
|
if strings.TrimSpace(cfg.AccessKeyID) == "" ||
|
|
strings.TrimSpace(cfg.AccessKeySecret) == "" ||
|
|
strings.TrimSpace(cfg.SignName) == "" ||
|
|
strings.TrimSpace(cfg.LoginTemplateCode) == "" {
|
|
return nil, ErrProviderConfigInvalid
|
|
}
|
|
|
|
client, err := dysms.NewClient(&openapi.Config{
|
|
AccessKeyId: dara.String(strings.TrimSpace(cfg.AccessKeyID)),
|
|
AccessKeySecret: dara.String(strings.TrimSpace(cfg.AccessKeySecret)),
|
|
Endpoint: dara.String(cfg.Endpoint),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &AliyunProvider{
|
|
client: client,
|
|
signName: strings.TrimSpace(cfg.SignName),
|
|
loginTemplateCode: strings.TrimSpace(cfg.LoginTemplateCode),
|
|
log: log,
|
|
}, nil
|
|
}
|
|
|
|
func (p *AliyunProvider) SendLoginCode(ctx context.Context, phone string, code string) error {
|
|
params, err := json.Marshal(map[string]string{"code": code})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req := &dysms.SendSmsRequest{}
|
|
req.SetPhoneNumbers(phone)
|
|
req.SetSignName(p.signName)
|
|
req.SetTemplateCode(p.loginTemplateCode)
|
|
req.SetTemplateParam(string(params))
|
|
|
|
resp, err := p.client.SendSmsWithContext(ctx, req, &dara.RuntimeOptions{})
|
|
if err != nil {
|
|
if p.log != nil {
|
|
p.log.Warn("aliyun sms send failed", zap.String("phone", maskPhone(phone)), zap.Error(err))
|
|
}
|
|
return fmt.Errorf("aliyun sms send failed: %w", err)
|
|
}
|
|
if resp == nil || resp.Body == nil {
|
|
return fmt.Errorf("aliyun sms empty response")
|
|
}
|
|
|
|
resultCode := dara.StringValue(resp.Body.Code)
|
|
if resultCode != "OK" {
|
|
resultMessage := dara.StringValue(resp.Body.Message)
|
|
if p.log != nil {
|
|
p.log.Warn(
|
|
"aliyun sms rejected",
|
|
zap.String("phone", maskPhone(phone)),
|
|
zap.String("request_id", dara.StringValue(resp.Body.RequestId)),
|
|
zap.String("code", resultCode),
|
|
zap.String("message", resultMessage),
|
|
)
|
|
}
|
|
providerErr := &ProviderError{Code: resultCode, Message: resultMessage}
|
|
if resultCode == "isv.BUSINESS_LIMIT_CONTROL" {
|
|
providerErr.Err = ErrProviderRateLimited
|
|
}
|
|
return providerErr
|
|
}
|
|
|
|
if p.log != nil {
|
|
p.log.Info(
|
|
"aliyun sms sent",
|
|
zap.String("phone", maskPhone(phone)),
|
|
zap.String("request_id", dara.StringValue(resp.Body.RequestId)),
|
|
zap.String("biz_id", dara.StringValue(resp.Body.BizId)),
|
|
)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func maskPhone(phone string) string {
|
|
if len(phone) < 7 {
|
|
return phone
|
|
}
|
|
return phone[:3] + "****" + phone[len(phone)-4:]
|
|
}
|