From ce72a172b083703ee1dcc3b6ac2aa21648d2294d Mon Sep 17 00:00:00 2001 From: Yang Luo Date: Thu, 7 Dec 2023 16:59:41 +0800 Subject: [PATCH] feat: add back Custom HTTP SMS provider --- object/sms.go | 2 + object/sms_custom.go | 76 +++++++++++++++++++++++++++++++++++++ web/src/ProviderEditPage.js | 74 +++++++++++++++++++++++++++--------- web/src/Setting.js | 6 +++ 4 files changed, 141 insertions(+), 17 deletions(-) create mode 100644 object/sms_custom.go diff --git a/object/sms.go b/object/sms.go index 85f3d33b..68d27076 100644 --- a/object/sms.go +++ b/object/sms.go @@ -26,6 +26,8 @@ func getSmsClient(provider *Provider) (sender.SmsClient, error) { if provider.Type == sender.HuaweiCloud || provider.Type == sender.AzureACS { client, err = sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.ProviderUrl, provider.AppId) + } else if provider.Type == "Custom HTTP SMS" { + client, err = newHttpSmsClient(provider.Endpoint, provider.Method, provider.Title) } else { client, err = sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.AppId) } diff --git a/object/sms_custom.go b/object/sms_custom.go new file mode 100644 index 00000000..acddfe0f --- /dev/null +++ b/object/sms_custom.go @@ -0,0 +1,76 @@ +// 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 object + +import ( + "bytes" + "fmt" + "net/http" + + "github.com/casdoor/casdoor/proxy" +) + +type HttpSmsClient struct { + endpoint string + method string + paramName string +} + +func newHttpSmsClient(endpoint string, method string, paramName string) (*HttpSmsClient, error) { + client := &HttpSmsClient{ + endpoint: endpoint, + method: method, + paramName: paramName, + } + return client, nil +} + +func (c *HttpSmsClient) SendMessage(param map[string]string, targetPhoneNumber ...string) error { + phoneNumber := targetPhoneNumber[0] + content := param["code"] + + req, err := http.NewRequest(c.method, c.endpoint, bytes.NewBufferString(content)) + if err != nil { + return err + } + + if c.method == "POST" { + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.PostForm = map[string][]string{ + "phoneNumber": targetPhoneNumber, + c.paramName: {content}, + } + } else if c.method == "GET" { + q := req.URL.Query() + q.Add("phoneNumber", phoneNumber) + q.Add(c.paramName, content) + req.URL.RawQuery = q.Encode() + } else { + return fmt.Errorf("HttpSmsClient's SendMessage() error, unsupported method: %s", c.method) + } + + httpClient := proxy.DefaultHttpClient + resp, err := httpClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("HttpSmsClient's SendMessage() error, custom HTTP SMS request failed with status: %s", resp.Status) + } + + return err +} diff --git a/web/src/ProviderEditPage.js b/web/src/ProviderEditPage.js index ced36140..b49ecbb5 100644 --- a/web/src/ProviderEditPage.js +++ b/web/src/ProviderEditPage.js @@ -521,6 +521,10 @@ class ProviderEditPage extends React.Component { this.updateProviderField("scopes", "openid profile email"); this.updateProviderField("customTokenUrl", "https://door.casdoor.com/api/login/oauth/access_token"); this.updateProviderField("customUserInfoUrl", "https://door.casdoor.com/api/userinfo"); + } else if (value === "Custom HTTP SMS") { + this.updateProviderField("endpoint", "https://example.com/send-custom-http"); + this.updateProviderField("method", "GET"); + this.updateProviderField("title", "code"); } else if (value === "Custom HTTP") { this.updateProviderField("method", "GET"); this.updateProviderField("title", ""); @@ -668,6 +672,7 @@ class ProviderEditPage extends React.Component { (this.state.provider.category === "Captcha" && this.state.provider.type === "Default") || (this.state.provider.category === "Web3") || (this.state.provider.category === "Storage" && this.state.provider.type === "Local File System") || + (this.state.provider.category === "SMS" && this.state.provider.type === "Custom HTTP SMS") || (this.state.provider.category === "Notification" && (this.state.provider.type === "Google Chat" || this.state.provider.type === "Custom HTTP")) ? null : ( { @@ -756,7 +761,7 @@ class ProviderEditPage extends React.Component { ) } - {this.state.provider.category === "Storage" ? ( + {this.state.provider.category === "Storage" || this.state.provider.type === "Custom HTTP SMS" ? (
{["Local File System"].includes(this.state.provider.type) ? null : ( @@ -770,7 +775,7 @@ class ProviderEditPage extends React.Component { )} - {["Local File System", "MinIO", "Tencent Cloud COS", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : ( + {["Custom HTTP SMS", "Local File System", "MinIO", "Tencent Cloud COS", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : ( {Setting.getLabel(i18next.t("provider:Endpoint (Intranet)"), i18next.t("provider:Region endpoint for Intranet"))} : @@ -782,7 +787,7 @@ class ProviderEditPage extends React.Component { )} - {["Local File System"].includes(this.state.provider.type) ? null : ( + {["Custom HTTP SMS", "Local File System"].includes(this.state.provider.type) ? null : ( {Setting.getLabel(i18next.t("provider:Bucket"), i18next.t("provider:Bucket - Tooltip"))} : @@ -794,17 +799,19 @@ class ProviderEditPage extends React.Component { )} - - - {Setting.getLabel(i18next.t("provider:Path prefix"), i18next.t("provider:Path prefix - Tooltip"))} : - - - { - this.updateProviderField("pathPrefix", e.target.value); - }} /> - - - {["MinIO", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : ( + {["Custom HTTP SMS"].includes(this.state.provider.type) ? null : ( + + + {Setting.getLabel(i18next.t("provider:Path prefix"), i18next.t("provider:Path prefix - Tooltip"))} : + + + { + this.updateProviderField("pathPrefix", e.target.value); + }} /> + + + )} + {["Custom HTTP SMS", "MinIO", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : ( {Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} : @@ -974,7 +981,7 @@ class ProviderEditPage extends React.Component { ) : this.state.provider.category === "SMS" ? ( - {["Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS"].includes(this.state.provider.type) ? + {["Custom HTTP SMS", "Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS"].includes(this.state.provider.type) ? null : ( @@ -988,7 +995,7 @@ class ProviderEditPage extends React.Component { ) } - {["Infobip SMS"].includes(this.state.provider.type) ? + {["Custom HTTP SMS", "Infobip SMS"].includes(this.state.provider.type) ? null : ( @@ -1002,6 +1009,39 @@ class ProviderEditPage extends React.Component { ) } + { + !["Custom HTTP SMS"].includes(this.state.provider.type) ? null : ( + + + + {Setting.getLabel(i18next.t("general:Method"), i18next.t("provider:Method - Tooltip"))} : + + + + + + + + {Setting.getLabel(i18next.t("provider:Parameter"), i18next.t("provider:Parameter - Tooltip"))} : + + + { + this.updateProviderField("title", e.target.value); + }} /> + + + + ) + } {Setting.getLabel(i18next.t("provider:SMS Test"), i18next.t("provider:SMS Test - Tooltip"))} : @@ -1026,7 +1066,7 @@ class ProviderEditPage extends React.Component { diff --git a/web/src/Setting.js b/web/src/Setting.js index 58cbfd59..dfd1607f 100644 --- a/web/src/Setting.js +++ b/web/src/Setting.js @@ -143,6 +143,10 @@ export const OtherProviderInfo = { logo: `${StaticBaseUrl}/img/social_msg91.ico`, url: "https://control.msg91.com/app/", }, + "Custom HTTP SMS": { + logo: `${StaticBaseUrl}/img/social_default.png`, + url: "https://casdoor.org/docs/provider/sms/overview", + }, "Mock SMS": { logo: `${StaticBaseUrl}/img/social_default.png`, url: "", @@ -989,6 +993,8 @@ export function getProviderTypeOptions(category) { {id: "Aliyun SMS", name: "Alibaba Cloud SMS"}, {id: "Amazon SNS", name: "Amazon SNS"}, {id: "Azure ACS", name: "Azure ACS"}, + {id: "Custom HTTP SMS", name: "Custom HTTP SMS"}, + {id: "Mock SMS", name: "Mock SMS"}, {id: "Infobip SMS", name: "Infobip SMS"}, {id: "Tencent Cloud SMS", name: "Tencent Cloud SMS"}, {id: "Baidu Cloud SMS", name: "Baidu Cloud SMS"},