From 31654c8e15e21b79ee941d3170cc6619e885727a Mon Sep 17 00:00:00 2001 From: JustSong Date: Sat, 5 Nov 2022 11:57:51 +0800 Subject: [PATCH] WeChat related setting is done --- README.md | 10 ++- common/constants.go | 8 ++ controller/misc.go | 22 ++++++ controller/option.go | 3 +- middleware/cors.go | 2 +- model/option.go | 15 ++++ router/api-router.go | 1 + web/src/components/WeChatSetting.js | 109 ++++++++++++++++++++++++++++ web/src/pages/Setting/index.js | 9 +++ 9 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 web/src/components/WeChatSetting.js diff --git a/README.md b/README.md index 0d13bfa..b90a1b0 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,17 @@ + [ ] Access Token 中控服务器 ## 用法 -1. 从 [GitHub Releases](https://github.com/songquanpeng/wechat-server/releases/latest) 下载可执行文件. +1. 从 [GitHub Releases](https://github.com/songquanpeng/wechat-server/releases/latest) 下载可执行文件。 2. 运行: 1. `chmod u+x wechat-server` 2. `./wechat-server --port 3000` -3. 初始账户用户名为 `root`,密码为 `123456`。 +3. 初始账户用户名为 `root`,密码为 `123456`,记得登录后立刻修改密码。 +4. 前往[微信公众号配置页面 -> 设置与开发 -> 基本配置](https://mp.weixin.qq.com/)获取 AppID 和 AppSecret,并在我们的配置页面填入上述信息,另外还需要配置 IP 白名单,按照页面上的提示完成即可。 +5. 前往[微信公众号配置页面 -> 设置与开发 -> 基本配置](https://mp.weixin.qq.com/)填写以下配置: + 1. `URL` 填:`https:///api/wechat_verification` + 2. `Token` 首先在我们的配置页面随便填写一个 Token,然后在微信公众号的配置页面填入同一个 Token 即可。 + 3. `EncodingAESKey` 点随机生成,然后在我们的配置页面填入该值。 + 4. 消息加解密方式选择明文模式。 ## 配置 系统本身开箱即用。 diff --git a/common/constants.go b/common/constants.go index 69c0fed..b20fe13 100644 --- a/common/constants.go +++ b/common/constants.go @@ -12,6 +12,14 @@ var SystemName = "微信服务器" var ServerAddress = "http://localhost:3000" var FooterHTML = "" +// Any options with "Secret", "Token", "Key" in its key won't be return by GetOptions + +var WeChatToken = "" +var WeChatAppID = "" +var WeChatAppSecret = "" +var WeChatEncodingAESKey = "" +var WeChatOwnerID = "" + var SessionSecret = uuid.New().String() var SQLitePath = ".wechat-server.db" diff --git a/controller/misc.go b/controller/misc.go index 3d40e28..d60133d 100644 --- a/controller/misc.go +++ b/controller/misc.go @@ -1,9 +1,13 @@ package controller import ( + "crypto/sha1" + "encoding/hex" "fmt" "github.com/gin-gonic/gin" "net/http" + "sort" + "strings" "wechat-server/common" "wechat-server/model" ) @@ -36,6 +40,24 @@ func GetNotice(c *gin.Context) { return } +func WeChatVerification(c *gin.Context) { + // https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html + signature := c.Query("signature") + timestamp := c.Query("timestamp") + nonce := c.Query("nonce") + echoStr := c.Query("echostr") + arr := []string{common.WeChatToken, timestamp, nonce} + sort.Strings(arr) + str := strings.Join(arr, "") + hash := sha1.Sum([]byte(str)) + hexStr := hex.EncodeToString(hash[:]) + if signature == hexStr { + c.String(http.StatusOK, echoStr) + } else { + c.Status(http.StatusForbidden) + } +} + func SendEmailVerification(c *gin.Context) { email := c.Query("email") if err := common.Validate.Var(email, "required,email"); err != nil { diff --git a/controller/option.go b/controller/option.go index 7dee302..d4e7729 100644 --- a/controller/option.go +++ b/controller/option.go @@ -4,6 +4,7 @@ import ( "encoding/json" "github.com/gin-gonic/gin" "net/http" + "strings" "wechat-server/common" "wechat-server/model" ) @@ -12,7 +13,7 @@ func GetOptions(c *gin.Context) { var options []*model.Option common.OptionMapRWMutex.Lock() for k, v := range common.OptionMap { - if k == "SMTPToken" || k == "GitHubClientSecret" { + if strings.Contains(k, "Token") || strings.Contains(k, "Secret") || strings.Contains(k, "Key") { continue } options = append(options, &model.Option{ diff --git a/middleware/cors.go b/middleware/cors.go index a4a6afc..76dd938 100644 --- a/middleware/cors.go +++ b/middleware/cors.go @@ -15,6 +15,6 @@ func CORS() gin.HandlerFunc { config.MaxAge = 12 * time.Hour // if you want to allow all origins, comment the following two lines config.AllowAllOrigins = false - //config.AllowedOrigins = []string{"https://wechat-server.vercel.app"} + config.AllowedOrigins = []string{"https://wechat-server.vercel.app"} return cors.New(config) } diff --git a/model/option.go b/model/option.go index 37e8845..51c895f 100644 --- a/model/option.go +++ b/model/option.go @@ -38,6 +38,11 @@ func InitOptionMap() { common.OptionMap["ServerAddress"] = "" common.OptionMap["GitHubClientId"] = "" common.OptionMap["GitHubClientSecret"] = "" + common.OptionMap["WeChatToken"] = "" + common.OptionMap["WeChatAppID"] = "" + common.OptionMap["WeChatAppSecret"] = "" + common.OptionMap["WeChatEncodingAESKey"] = "" + common.OptionMap["WeChatOwnerID"] = "" common.OptionMapRWMutex.Unlock() options, _ := AllOption() for _, option := range options { @@ -106,5 +111,15 @@ func updateOptionMap(key string, value string) { common.GitHubClientSecret = value case "FooterHTML": common.FooterHTML = value + case "WeChatToken": + common.WeChatToken = value + case "WeChatAppID": + common.WeChatAppID = value + case "WeChatAppSecret": + common.WeChatAppSecret = value + case "WeChatEncodingAESKey": + common.WeChatEncodingAESKey = value + case "WeChatOwnerID": + common.WeChatOwnerID = value } } diff --git a/router/api-router.go b/router/api-router.go index 9edcebc..2de5377 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -12,6 +12,7 @@ func SetApiRouter(router *gin.Engine) { { apiRouter.GET("/status", controller.GetStatus) apiRouter.GET("/notice", controller.GetNotice) + apiRouter.GET("/wechat_verification", controller.WeChatVerification) apiRouter.GET("/verification", middleware.CriticalRateLimit(), controller.SendEmailVerification) apiRouter.GET("/reset_password", middleware.CriticalRateLimit(), controller.SendPasswordResetEmail) apiRouter.GET("/user/reset", controller.SendNewPasswordEmail) diff --git a/web/src/components/WeChatSetting.js b/web/src/components/WeChatSetting.js new file mode 100644 index 0000000..f1cd7ff --- /dev/null +++ b/web/src/components/WeChatSetting.js @@ -0,0 +1,109 @@ +import React, { useEffect, useState } from 'react'; +import { Form, Grid } from 'semantic-ui-react'; +import { API, showError } from '../helpers'; + +const WeChatSetting = () => { + let [inputs, setInputs] = useState({ + WeChatToken: '', + WeChatAppID: '', + WeChatAppSecret: '', + WeChatEncodingAESKey: '', + WeChatOwnerID: '', + }); + let [loading, setLoading] = useState(false); + + const getOptions = async () => { + const res = await API.get('/api/option'); + const { success, message, data } = res.data; + if (success) { + let newInputs = {}; + data.forEach((item) => { + if (item.key.startsWith('WeChat')) { + newInputs[item.key] = item.value; + } + }); + setInputs(newInputs); + } else { + showError(message); + } + }; + + useEffect(() => { + getOptions().then(); + }, []); + + const updateOption = async (key, value) => { + setLoading(true); + const res = await API.put('/api/option', { + key, + value, + }); + const { success, message } = res.data; + if (success) { + setInputs((inputs) => ({ ...inputs, [key]: value })); + } else { + showError(message); + } + setLoading(false); + }; + + const handleInputChange = async (e, { name, value }) => { + await updateOption(name, value); + }; + + return ( + + +
+ + + + + + + + + + + + + + + +
+
+
+ ); +}; + +export default WeChatSetting; diff --git a/web/src/pages/Setting/index.js b/web/src/pages/Setting/index.js index d496968..5290618 100644 --- a/web/src/pages/Setting/index.js +++ b/web/src/pages/Setting/index.js @@ -4,6 +4,7 @@ import SystemSetting from '../../components/SystemSetting'; import { Link } from 'react-router-dom'; import { API, copy, isRoot, showError, showSuccess } from '../../helpers'; import { marked } from 'marked'; +import WeChatSetting from '../../components/WeChatSetting'; const Setting = () => { const [showUpdateModal, setShowUpdateModal] = useState(false); @@ -67,6 +68,14 @@ const Setting = () => { ), }); + panes.push({ + menuItem: '微信设置', + render: () => ( + + + + ), + }); panes.push({ menuItem: '其他设置', render: () => (