From 3dacd6c5ccf01963dbd078b561549c9049b600e9 Mon Sep 17 00:00:00 2001 From: iyear Date: Sat, 13 Mar 2021 13:15:31 +0800 Subject: [PATCH] Refactor --- bots/control.go | 28 ++------ bots/handle.go | 12 ++-- core/client.go | 148 ++++++++++++++++++++++++++++++++++++++++ outlook/outlook.go | 164 --------------------------------------------- 4 files changed, 158 insertions(+), 194 deletions(-) delete mode 100644 outlook/outlook.go diff --git a/bots/control.go b/bots/control.go index 578bb2d..726b02b 100644 --- a/bots/control.go +++ b/bots/control.go @@ -8,7 +8,6 @@ import ( tb "gopkg.in/tucnak/telebot.v2" "main/core" "main/logger" - "main/outlook" "main/util" "strconv" "strings" @@ -27,43 +26,36 @@ func BindUser(m *tb.Message, cid, cse string) error { } logger.Println("Alias: " + tmp[1]) Alias := tmp[1] + client := core.NewClient(cid, cse) code := util.GetURLValue(tmp[0], "code") //fmt.Println(code) - access, refresh, err := MSFirGetToken(code, cid, cse) + err := client.GetTokenWithCode(code) if err != nil { - logger.Println("%d Bind error:GetRefreshToken %s \n", m.Chat.ID, err.Error()) return err } - - //token has gotten bot.Send(m.Chat, "Token获取成功!") - info, err := outlook.GetUserInfo(access) + info, err := client.GetUserInfo() //fmt.Println("TgId:%d Refresh Token: %s\n", m.Chat.ID, refresh) if err != nil { - logger.Println("%d Bind error:Getinfo %s \n", m.Chat.ID, err.Error()) return err } - var u core.Client u.TgId = m.Chat.ID - u.RefreshToken = refresh + u.RefreshToken = client.RefreshToken //TG的Data传递最高64bytes,一些MsId超过了报错BUTTON_DATA_INVALID (0),采取md5 u.MsId = util.Get16MD5Encode(gjson.Get(info, "id").String()) u.Uptime = time.Now().Unix() - logger.Println(u.Uptime) u.Alias = Alias u.ClientId = cid u.ClientSecret = cse u.Other = "" //MS User Is Exist if MSAppIsExist(u.TgId, u.ClientId) { - logger.Println("%d Bind error:MSUserHasExisted\n", m.Chat.ID) return errors.New("该应用已经绑定过了,无需重复绑定") } //MS information has gotten bot.Send(m.Chat, "MS_ID(MD5): "+u.MsId+"\nuserPrincipalName: "+gjson.Get(info, "userPrincipalName").String()+"\ndisplayName: "+gjson.Get(info, "displayName").String()+"\n") if ok, err := core.AddData(u); !ok { - logger.Println("%d Bind error: %s\n", m.Chat.ID, err) return err } logger.Println("%d Bind Successfully!\n", m.Chat.ID) @@ -118,16 +110,8 @@ func SignTask() { tmpBtn := &tb.ReplyMarkup{InlineKeyboard: inlineKeys} se := u.MsId + " ( @" + chat.Username + " )" - access, newRefreshToken, err := outlook.GetToken(u.RefreshToken, u.ClientId, u.ClientSecret) - - if err != nil { - logger.Println(u.MsId+" ", err) - bot.Send(chat, pre+gjson.Get(err.Error(), "error").String(), tmpBtn) - SignErr = append(SignErr, se) - ErrorTimes[u.MsId]++ - continue - } - if ok, err := outlook.GetOutLookMails(access); !ok { + client := core.NewClient(u.ClientId, u.ClientSecret) + if err := client.GetOutlookMails(); err != nil { logger.Println(u.MsId+" ", err) bot.Send(chat, pre+gjson.Get(err.Error(), "error").String(), tmpBtn) ErrorTimes[u.MsId]++ diff --git a/bots/handle.go b/bots/handle.go index 1dab746..36ccd81 100644 --- a/bots/handle.go +++ b/bots/handle.go @@ -8,7 +8,6 @@ import ( "io/ioutil" "main/core" "main/logger" - "main/outlook" "main/util" "os" "path/filepath" @@ -25,10 +24,8 @@ const ( /my 查看已绑定账户信息 /bind 绑定新账户 /unbind 解绑账户 - /export 导出账户信息(JSON格式) + /export 导出账户信息(JSON) /help 帮助 - /task 手动执行一次任务(管理员) - /log 获取最近日志文件(管理员) 源码及使用方法:https://github.com/iyear/E5SubBot ` ) @@ -110,7 +107,7 @@ func bMyInlineBtn(c *tb.Callback) { func bBind1(m *tb.Message) { logger.Println(strconv.FormatInt(m.Chat.ID, 10) + " Start Bind") logger.Println("ReApp: " + strconv.FormatInt(m.Chat.ID, 10)) - bot.Send(m.Chat, "应用注册: [点击直达]("+outlook.GetMSRegisterAppUrl()+")", tb.ModeMarkdown) + bot.Send(m.Chat, "应用注册: [点击直达]("+core.GetMSRegisterAppUrl()+")", tb.ModeMarkdown) _, err := bot.Send(m.Chat, "请回复client_id+空格+client_secret", &tb.ReplyMarkup{ForceReply: true}) if err != nil { logger.Println(err) @@ -131,7 +128,7 @@ func bBind2(m *tb.Message) { logger.Println("client_id: " + tmp[0] + " client_secret: " + tmp[1]) cid := tmp[0] cse := tmp[1] - bot.Send(m.Chat, "授权账户: [点击直达]("+outlook.GetMSAuthUrl(cid)+")", tb.ModeMarkdown) + bot.Send(m.Chat, "授权账户: [点击直达]("+core.GetMSAuthUrl(cid)+")", tb.ModeMarkdown) _, err := bot.Send(m.Chat, "请回复http://localhost/…… + 空格 + 别名(用于管理)", &tb.ReplyMarkup{ForceReply: true}) if err != nil { logger.Println(err) @@ -194,7 +191,7 @@ func bExport(m *tb.Message) { ms.Other = u.Other MsMini = append(MsMini, ms) } - //MarshalIndent是为json+美化,/t表缩进 + //MarshalIndent json美化,/t缩进 export, err := json.MarshalIndent(MsMini, "", "\t") if err != nil { logger.Println(err) @@ -305,7 +302,6 @@ func bLogsInlineBtn(c *tb.Callback) { logfile := &tb.Document{File: tb.FromDisk(bLogBasePath + c.Data), FileName: c.Data, MIME: "text/plain"} _, err := bot.Send(c.Message.Chat, logfile) if err != nil { - logger.Println(err) return } bot.Respond(c) diff --git a/core/client.go b/core/client.go index ce30af8..a8b2df2 100644 --- a/core/client.go +++ b/core/client.go @@ -1,5 +1,14 @@ package core +import ( + "github.com/pkg/errors" + "github.com/tidwall/gjson" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + type Client struct { TgId int64 `gorm:"column:tg_id"` RefreshToken string `gorm:"column:refresh_token"` @@ -10,3 +19,142 @@ type Client struct { ClientSecret string `gorm:"column:client_secret"` Other string `gorm:"column:other"` } + +const ( + msApiUrl string = "https://login.microsoftonline.com" + msGraUrl string = "https://graph.microsoft.com" + redirectUri string = "http://localhost/e5sub" + scope string = "openid offline_access mail.read user.read" +) + +func NewClient(clientId string, clientSecret string) *Client { + return &Client{ + ClientId: clientId, + ClientSecret: clientSecret, + } +} +func GetMSAuthUrl(clientId string) string { + return "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=" + clientId + "&response_type=code&redirect_uri=" + url.QueryEscape(redirectUri) + "&response_mode=query&scope=" + url.QueryEscape(scope) +} +func GetMSRegisterAppUrl() string { + ru := "https://developer.microsoft.com/en-us/graph/quick-start?appID=_appId_&appName=_appName_&redirectUrl=http://localhost:8000&platform=option-windowsuniversal" + deeplink := "/quickstart/graphIO?publicClientSupport=false&appName=e5sub&redirectUrl=http://localhost/e5sub&allowImplicitFlow=false&ru=" + url.QueryEscape(ru) + appUrl := "https://apps.dev.microsoft.com/?deepLink=" + url.QueryEscape(deeplink) + return appUrl +} + +//return access_token and refresh_token +func (c *Client) GetTokenWithCode(code string) (error error) { + var r http.Request + client := &http.Client{} + r.ParseForm() + r.Form.Add("client_id", c.ClientId) + r.Form.Add("client_secret", c.ClientSecret) + r.Form.Add("grant_type", "authorization_code") + r.Form.Add("scope", scope) + r.Form.Add("code", code) + r.Form.Add("redirect_uri", redirectUri) + body := strings.NewReader(r.Form.Encode()) + req, err := http.NewRequest("POST", msApiUrl+"/common/oauth2/v2.0/token", body) + if err != nil { + return err + } + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + if gjson.Get(string(content), "token_type").String() == "Bearer" { + c.RefreshToken = gjson.Get(string(content), "refresh_token").String() + return nil + } + return errors.New(string(content)) +} + +//return access_token and new refresh token +func (c *Client) getToken() (access string) { + var r http.Request + client := &http.Client{} + r.ParseForm() + r.Form.Add("client_id", c.ClientId) + r.Form.Add("client_secret", c.ClientSecret) + r.Form.Add("grant_type", "refresh_token") + r.Form.Add("scope", scope) + r.Form.Add("refresh_token", c.RefreshToken) + r.Form.Add("redirect_uri", redirectUri) + body := strings.NewReader(r.Form.Encode()) + //fmt.Println(body) + req, err := http.NewRequest("POST", msApiUrl+"/common/oauth2/v2.0/token", body) + if err != nil { + return "" + } + resp, err := client.Do(req) + if err != nil { + return "" + } + defer resp.Body.Close() + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "" + } + //fmt.Println(string(content)) + //fmt.Println(gjson.Get(string(content), "access_token").String()) + if gjson.Get(string(content), "token_type").String() == "Bearer" { + c.RefreshToken = gjson.Get(string(content), "refresh_token").String() + return gjson.Get(string(content), "access_token").String() + } + return "" +} + +//Get User's Information +func (c *Client) GetUserInfo() (json string, error error) { + client := http.Client{} + req, err := http.NewRequest("GET", msGraUrl+"/v1.0/me", nil) + if err != nil { + return "", err + } + req.Header.Set("Authorization", c.getToken()) + resp, err := client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + if gjson.Get(string(content), "id").String() != "" { + //fmt.Println("UserName: " + gjson.Get(string(content), "displayName").String()) + return string(content), nil + } + return "", errors.New(string(content)) +} + +func (c *Client) GetOutlookMails() error { + client := http.Client{} + req, err := http.NewRequest("GET", msGraUrl+"/v1.0/me/messages", nil) + + if err != nil { + return err + } + req.Header.Set("Authorization", c.getToken()) + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + //fmt.Println(string(content)) + //这里的.需要转义,否则会按路径的方式解析 + if gjson.Get(string(content), "@odata\\.context").String() != "" { + return nil + } + return errors.New(string(content)) +} diff --git a/outlook/outlook.go b/outlook/outlook.go deleted file mode 100644 index 0fdbcd0..0000000 --- a/outlook/outlook.go +++ /dev/null @@ -1,164 +0,0 @@ -package outlook - -import ( - "errors" - "github.com/tidwall/gjson" - "io/ioutil" - "main/logger" - "net/http" - "net/url" - "strings" -) - -const ( - msApiUrl string = "https://login.microsoftonline.com" - msGraUrl string = "https://graph.microsoft.com" - redirectUri string = "http://localhost/e5sub" - scope string = "openid offline_access mail.read user.read" -) - -type msClient struct { - clientId string - clientSecret string -} - -func NewMSClient(clientId string, clientSecret string) *msClient { - return &msClient{ - clientId: clientId, - clientSecret: clientSecret, - } -} -func GetMSAuthUrl(clientId string) string { - return "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=" + clientId + "&response_type=code&redirect_uri=" + url.QueryEscape(redirectUri) + "&response_mode=query&scope=" + url.QueryEscape(scope) -} -func GetMSRegisterAppUrl() string { - ru := "https://developer.microsoft.com/en-us/graph/quick-start?appID=_appId_&appName=_appName_&redirectUrl=http://localhost:8000&platform=option-windowsuniversal" - deeplink := "/quickstart/graphIO?publicClientSupport=false&appName=e5sub&redirectUrl=http://localhost/e5sub&allowImplicitFlow=false&ru=" + url.QueryEscape(ru) - appUrl := "https://apps.dev.microsoft.com/?deepLink=" + url.QueryEscape(deeplink) - return appUrl -} - -//return access_token and refresh_token -func (c *msClient) GetTokenWithCode(code string) (access string, refresh string, Error error) { - var r http.Request - client := &http.Client{} - r.ParseForm() - r.Form.Add("client_id", c.clientId) - r.Form.Add("client_secret", c.clientSecret) - r.Form.Add("grant_type", "authorization_code") - r.Form.Add("scope", scope) - r.Form.Add("code", code) - r.Form.Add("redirect_uri", redirectUri) - body := strings.NewReader(r.Form.Encode()) - req, err := http.NewRequest("POST", msApiUrl+"/common/oauth2/v2.0/token", body) - if err != nil { - logger.Println(err) - return "", "", err - } - resp, err := client.Do(req) - if err != nil { - logger.Println(err) - return "", "", err - } - defer resp.Body.Close() - content, err := ioutil.ReadAll(resp.Body) - if err != nil { - logger.Println(err) - return "", "", err - } - if gjson.Get(string(content), "token_type").String() == "Bearer" { - return gjson.Get(string(content), "access_token").String(), gjson.Get(string(content), "refresh_token").String(), nil - } - return "", "", errors.New(string(content)) -} - -//return access_token and new refresh token -func (c *msClient) GetToken(refreshToken string) (access string, newRefreshToken string, Error error) { - var r http.Request - client := &http.Client{} - r.ParseForm() - r.Form.Add("client_id", c.clientId) - r.Form.Add("client_secret", c.clientSecret) - r.Form.Add("grant_type", "refresh_token") - r.Form.Add("scope", scope) - r.Form.Add("refresh_token", refreshToken) - r.Form.Add("redirect_uri", redirectUri) - body := strings.NewReader(r.Form.Encode()) - //fmt.Println(body) - req, err := http.NewRequest("POST", msApiUrl+"/common/oauth2/v2.0/token", body) - if err != nil { - logger.Println(err) - return "", "", err - } - resp, err := client.Do(req) - if err != nil { - logger.Println(err) - return "", "", err - } - defer resp.Body.Close() - content, err := ioutil.ReadAll(resp.Body) - if err != nil { - logger.Println(err) - return "", "", err - } - //fmt.Println(string(content)) - //fmt.Println(gjson.Get(string(content), "access_token").String()) - if gjson.Get(string(content), "token_type").String() == "Bearer" { - return gjson.Get(string(content), "access_token").String(), gjson.Get(string(content), "refresh_token").String(), nil - } - return "", "", errors.New(string(content)) -} - -//Get User's Information -func GetUserInfo(accesstoken string) (json string, Error error) { - client := http.Client{} - req, err := http.NewRequest("GET", msGraUrl+"/v1.0/me", nil) - if err != nil { - logger.Println(err) - return "", err - } - req.Header.Set("Authorization", accesstoken) - resp, err := client.Do(req) - if err != nil { - logger.Println(err) - return "", err - } - defer resp.Body.Close() - content, err := ioutil.ReadAll(resp.Body) - if err != nil { - logger.Println(err) - return "", err - } - if gjson.Get(string(content), "id").String() != "" { - //fmt.Println("UserName: " + gjson.Get(string(content), "displayName").String()) - return string(content), nil - } - return "", errors.New(string(content)) -} - -func GetOutLookMails(accesstoken string) (bool, error) { - client := http.Client{} - req, err := http.NewRequest("GET", msGraUrl+"/v1.0/me/messages", nil) - if err != nil { - logger.Println(err) - return false, err - } - req.Header.Set("Authorization", accesstoken) - resp, err := client.Do(req) - if err != nil { - logger.Println(err) - return false, err - } - defer resp.Body.Close() - content, err := ioutil.ReadAll(resp.Body) - if err != nil { - logger.Println(err) - return false, err - } - //fmt.Println(string(content)) - //这里的.需要转义,否则会按路径的方式解析 - if gjson.Get(string(content), "@odata\\.context").String() != "" { - return true, nil - } - return false, errors.New(string(content)) -}