This commit is contained in:
iyear 2021-03-13 13:15:31 +08:00
parent 90248dc946
commit 3dacd6c5cc
4 changed files with 158 additions and 194 deletions

View File

@ -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]++

View File

@ -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)

View File

@ -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))
}

View File

@ -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))
}