From bf4c467c022edc02f7617b786980000bd4915e22 Mon Sep 17 00:00:00 2001 From: Ron <113475097+waffle-frame@users.noreply.github.com> Date: Sun, 3 Mar 2024 20:05:55 +0500 Subject: [PATCH] feat: implemented SMS provider "OSON SMS" (#39) * sms provider 'OSON SMS' implemented * improvement of oson sms SMS service; changed module to original value; 'OSON SMS' provider is included in the list of README.md * feat: add 'OSON SMS' provider * Update go.mod --------- Co-authored-by: Eric Luo --- README.md | 28 +++++++++++++ basic.go | 3 ++ oson.go | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 oson.go diff --git a/README.md b/README.md index 55e82b7..9134aaf 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ We support the following SMS providers, welcome to contribute. - [UCloud](https://www.ucloud.cn/site/product/usms.html) - [Huyi](https://www.ihuyi.com/) - [Netgsm](https://www.netgsm.com.tr/) +- [Oson Sms](https://osonsms.com/) ## Installation @@ -164,6 +165,33 @@ func main() { } ``` +### Oson Sms + +- senderId: is `login` +- secretAccessKey: is `hash` +- signName: is `from` +- templateCode: is `message` + +```go +package main + +func main() { + client, err := go_sms_sender.NewSmsClient(go_sms_senderOsonSms, "senderId", "secretAccessKey", "signName", "templateCode") + if err != nil { + panic(err) + } + + params := map[string]string{} + params["code"] = "123456" + phoneNumer := "+992123456789" + err = client.SendMessage(params, phoneNumer) + if err != nil { + panic(err) + } +} +``` + + ### Running Tests To run tests for the `go-sms-sender` library, navigate to the root folder of the project in your terminal and execute the following command: diff --git a/basic.go b/basic.go index 35e24f0..9e68ac7 100644 --- a/basic.go +++ b/basic.go @@ -34,6 +34,7 @@ const ( Huyi = "Huyi SMS" MockSms = "Mock SMS" Netgsm = "Netgsm SMS" + OsonSms = "OSON SMS" ) type SmsClient interface { @@ -76,6 +77,8 @@ func NewSmsClient(provider string, accessId string, accessKey string, sign strin return GetNetgsmClient(accessId, accessKey, sign, template) case MockSms: return NewMocker(accessId, accessKey, sign, template, other) + case OsonSms: + return GetOsonClient(accessId, accessKey, sign, template) default: return nil, fmt.Errorf("unsupported provider: %s", provider) } diff --git a/oson.go b/oson.go new file mode 100644 index 0000000..c95f89e --- /dev/null +++ b/oson.go @@ -0,0 +1,120 @@ +// Copyright 2023 The Casdoor Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package go_sms_sender + +import ( + "crypto/sha256" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + "time" + + "github.com/google/uuid" +) + +type OsonClient struct { + Endpoint string + SenderID string + SecretAccessHash string + Sign string + Message string +} + +type OsonResponse struct { + Status string // ok + Timestamp time.Time // 2017-07-07 16:58:12 + TxnId string // f89xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe0b + MsgId uint // 40127 + SmscMsgId string // 45f22479 + SmscMsgStatus string // success + SmscMsgParts string // 1 +} + +func GetOsonClient(senderId, secretAccessHash, sign, message string) (*OsonClient, error) { + return &OsonClient{ + Endpoint: "https://api.osonsms.com/sendsms_v1.php", + SenderID: senderId, + SecretAccessHash: secretAccessHash, + Sign: sign, + Message: message, + }, nil +} + +func (c *OsonClient) SendMessage(param map[string]string, targetPhoneNumber ...string) (err error) { + // Init http client for make request to sms center. Set a timeout of 25+ + // seconds to ensure that the response from the SMS center has been + // processed. + client := &http.Client{ + Timeout: 20 * time.Second, + } + + if c.Message == "" { + c.Message = fmt.Sprintf("Hello. Your authorization code: %s", param["code"]) + } else { + c.Message += param["code"] + } + + txnID := uuid.New() + buildStrHash := strings.Join([]string{txnID.String(), c.SenderID, c.Sign, targetPhoneNumber[0], c.SecretAccessHash}, ";") + + hash := sha256.New() + hash.Write([]byte(buildStrHash)) + bs := hash.Sum(nil) + strHash := fmt.Sprintf("%x", bs) + + urlLink, err := url.Parse(c.Endpoint) + if err != nil { + return + } + + urlParams := url.Values{} + urlParams.Add("from", c.Sign) + urlParams.Add("phone_number", targetPhoneNumber[0]) + urlParams.Add("msg", c.Message) + urlParams.Add("str_hash", strHash) + urlParams.Add("txn_id", txnID.String()) + urlParams.Add("login", c.SenderID) + + urlLink.RawQuery = urlParams.Encode() + + request, err := http.NewRequest(http.MethodGet, urlLink.String(), nil) + if err != nil { + return + } + + resp, err := client.Do(request) + if err != nil { + return + } + + resultBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + var result OsonResponse + if err = json.Unmarshal(resultBytes, &result); err != nil { + return + } + + if result.Status != "ok" { + return fmt.Errorf("sms service returned error status not 200: Status Code: %d Error: %s", resp.StatusCode, string(resultBytes)) + } + + return +}