修复授权方式
This commit is contained in:
parent
0deaeaa2cc
commit
c40e2df6fc
21
README.md
21
README.md
@ -27,13 +27,14 @@ E5订阅为开发者订阅,只要调用相关API就有可能续期
|
||||
|
||||
## 使用方法
|
||||
|
||||
在机器人对话框输入**/bind**,进入授权页面,用E5订阅的账户登录。
|
||||
1. 在机器人对话框输入 **/bind**
|
||||
2. 注册应用,使用E5主账号或同域账号登录
|
||||
3. 复制client_secret和client_id,以 `client_id client_secret`格式回复
|
||||
4. 获得授权链接,使用E5主账号或同域账号登录
|
||||
5. 授权后会跳转至`http://localhost/e5sub……`
|
||||
6. 复制整个浏览框内容,在机器人对话框回复 `链接+空格+别名(用于管理账户)`
|
||||
|
||||
授权后会跳转至`http://localhost/e5sub……`
|
||||
|
||||
复制整个浏览框内容,在机器人对话框回复 `链接+空格+别名(用于管理账户)`
|
||||
|
||||
例如:`http://localhost/e5sub/?code=abcd mye5`,等待机器人绑定后即完成
|
||||
例如:`http://localhost/e5sub/?code=abcd MyE5`,等待机器人绑定后即完成
|
||||
|
||||
## 自行部署
|
||||
|
||||
@ -70,8 +71,6 @@ go build main.go
|
||||
bot_token: xxxxx
|
||||
#不需要socks5代理删去即可
|
||||
socks5: 127.0.0.1:1080
|
||||
#auth_url需要自己去Azure注册应用配置
|
||||
auth_url: https://login.microsoftonline.com/common/oauth2/v2.0/authorize?……
|
||||
#最大可绑定数
|
||||
bindmax: 3
|
||||
#mysql配置
|
||||
@ -109,18 +108,12 @@ Go在寒假里看过一段时间的《Golang核心编程》+Go官方的教程,
|
||||
|
||||
自行部署可能会有报错崩溃什么的,谅解一下吧。。用DEMO也行
|
||||
|
||||
如果有兴趣的大佬欢迎加入群组交流,但有些东西我可能听不太懂。
|
||||
|
||||
------
|
||||
|
||||
一开始用的sqlite数据库,加载的是<https://github.com/mattn/go-sqlite3> 驱动,结果等我写完了,CGO各种编译错误。
|
||||
|
||||
最后实在折腾不起来,只好改用MySQL(VPS上都是一键,Win上装MySQL也折腾了半天)
|
||||
|
||||
------
|
||||
|
||||
虽然自知写的垃圾,但也是第一个正式的Go Project……
|
||||
|
||||
## License
|
||||
|
||||
GPLv3
|
||||
21
control.go
21
control.go
@ -9,18 +9,18 @@ import (
|
||||
)
|
||||
|
||||
//If Successfully return "",else return error information
|
||||
func BindUser(m *tb.Message) string {
|
||||
func BindUser(m *tb.Message, cid, cse string) string {
|
||||
fmt.Printf("%d Begin Bind\n", m.Chat.ID)
|
||||
tmp := strings.Split(m.Text, " ")
|
||||
fmt.Println("alias: " + tmp[1])
|
||||
if len(tmp) != 2 {
|
||||
fmt.Printf("%d Bind error:Wrong Bind Format\n", m.Chat.ID)
|
||||
return "授权格式错误"
|
||||
}
|
||||
fmt.Println("alias: " + tmp[1])
|
||||
alias := tmp[1]
|
||||
code := GetURLValue(tmp[0], "code")
|
||||
fmt.Println(code)
|
||||
access, refresh := MSFirGetToken(code)
|
||||
access, refresh := MSFirGetToken(code, cid, cse)
|
||||
if refresh == "" {
|
||||
fmt.Printf("%d Bind error:GetRefreshToken\n", m.Chat.ID)
|
||||
return "获取RefreshToken失败"
|
||||
@ -42,12 +42,15 @@ func BindUser(m *tb.Message) string {
|
||||
u.msId = Get16MD5Encode(gjson.Get(info, "id").String())
|
||||
u.uptime = time.Now().Unix()
|
||||
fmt.Println(u.uptime)
|
||||
u.other = alias
|
||||
u.alias = alias
|
||||
u.clientId = cid
|
||||
u.clientSecret = cse
|
||||
u.other = ""
|
||||
//u.other = SetJsonValue(u.other, "sign", Get16MD5Encode(u.msId))
|
||||
//MS User Is Exist
|
||||
if MSUserIsExist(u.tgId, u.msId) {
|
||||
if MSAppIsExist(u.tgId, u.clientId) {
|
||||
fmt.Printf("%d Bind error:MSUserHasExisted\n", m.Chat.ID)
|
||||
return "该ID对应的用户已经绑定过了"
|
||||
return "该应用已经绑定过了,无需重复绑定"
|
||||
}
|
||||
//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")
|
||||
@ -66,11 +69,11 @@ func GetBindNum(tgId int64) int {
|
||||
}
|
||||
|
||||
//return true => exist
|
||||
func MSUserIsExist(tgId int64, msId string) bool {
|
||||
func MSAppIsExist(tgId int64, clientId string) bool {
|
||||
data := QueryDataByTG(db, tgId)
|
||||
var res MSData
|
||||
for _, res = range data {
|
||||
if res.msId == msId {
|
||||
if res.msId == clientId {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -83,7 +86,7 @@ func SignTask() {
|
||||
fmt.Println("Time:" + time.Now().Format("2006-01-02 15:04:05"))
|
||||
data := QueryDataAll(db)
|
||||
for _, u := range data {
|
||||
access := MSGetToken(u.refreshToken)
|
||||
access := MSGetToken(u.refreshToken, u.clientId, u.clientSecret)
|
||||
if access == "" {
|
||||
fmt.Println(u.msId + "Sign ERROR:AccessTokenGet")
|
||||
continue
|
||||
|
||||
66
handle.go
66
handle.go
@ -5,6 +5,7 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
tb "gopkg.in/tucnak/telebot.v2"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -12,6 +13,7 @@ const (
|
||||
bStartContent string = "欢迎使用E5SubBot!\n请输入\\help查看帮助"
|
||||
bHelpContent string = `
|
||||
命令:
|
||||
/notice 查看最新公告
|
||||
/my 查看已绑定账户信息
|
||||
/bind 绑定新账户
|
||||
/unbind 解绑账户
|
||||
@ -21,15 +23,16 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
UserStatus map[int64]int
|
||||
BindMaxNum int
|
||||
UserStatus map[int64]int
|
||||
UserCid map[int64]string
|
||||
UserCSecret map[int64]string
|
||||
BindMaxNum int
|
||||
)
|
||||
|
||||
const (
|
||||
USNone = iota
|
||||
USUnbind
|
||||
USWillBind
|
||||
USBind
|
||||
USBind1
|
||||
USBind2
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -42,17 +45,21 @@ func init() {
|
||||
BindMaxNum = viper.GetInt("bindmax")
|
||||
|
||||
UserStatus = make(map[int64]int)
|
||||
UserCid = make(map[int64]string)
|
||||
UserCSecret = make(map[int64]string)
|
||||
}
|
||||
func bStart(m *tb.Message) {
|
||||
bot.Send(m.Sender, bStartContent)
|
||||
bNotice(m)
|
||||
}
|
||||
func bMy(m *tb.Message) {
|
||||
data := QueryDataByTG(db, m.Chat.ID)
|
||||
var inlineKeys [][]tb.InlineButton
|
||||
for _, u := range data {
|
||||
fmt.Println(u)
|
||||
inlineBtn := tb.InlineButton{
|
||||
Unique: "my" + u.msId,
|
||||
Text: u.other,
|
||||
Text: u.alias,
|
||||
Data: u.msId,
|
||||
}
|
||||
bot.Handle(&inlineBtn, bMyInlineBtn)
|
||||
@ -63,26 +70,45 @@ func bMy(m *tb.Message) {
|
||||
func bMyInlineBtn(c *tb.Callback) {
|
||||
r := QueryDataByMS(db, c.Data)
|
||||
u := r[0]
|
||||
bot.Send(c.Message.Chat, "信息\n别名:"+u.other+"\nMS_ID(MD5): "+u.msId+"\n最近更新时间: "+time.Unix(u.uptime, 0).Format("2006-01-02 15:04:05"))
|
||||
bot.Send(c.Message.Chat, "信息\n别名:"+u.alias+"\nMS_ID(MD5): "+u.msId+"\nclient_id: "+u.clientId+"\n最近更新时间: "+time.Unix(u.uptime, 0).Format("2006-01-02 15:04:05"))
|
||||
bot.Respond(c)
|
||||
}
|
||||
func bBind(m *tb.Message) {
|
||||
tgId := m.Chat.ID
|
||||
fmt.Println("Auth: " + strconv.FormatInt(tgId, 10))
|
||||
bot.Send(m.Chat, "授权链接: [点击直达]("+authUrl+")", tb.ModeMarkdown)
|
||||
_, err := bot.Send(m.Chat, "回复格式:http://localhost/...+空格+别名(用于管理)", &tb.ReplyMarkup{ForceReply: true})
|
||||
func bBind1(m *tb.Message) {
|
||||
fmt.Println("ReApp: " + strconv.FormatInt(m.Chat.ID, 10))
|
||||
bot.Send(m.Chat, "应用注册: [点击直达]("+MSGetReAppUrl()+")", tb.ModeMarkdown)
|
||||
_, err := bot.Send(m.Chat, "请回复client_id+空格+client_secret", &tb.ReplyMarkup{ForceReply: true})
|
||||
if err == nil {
|
||||
UserStatus[m.Chat.ID] = USWillBind
|
||||
UserStatus[m.Chat.ID] = USBind1
|
||||
UserCid[m.Chat.ID] = m.Text
|
||||
}
|
||||
|
||||
}
|
||||
func bBind2(m *tb.Message) {
|
||||
fmt.Println("Auth: " + strconv.FormatInt(m.Chat.ID, 10))
|
||||
tmp := strings.Split(m.Text, " ")
|
||||
if len(tmp) != 2 {
|
||||
fmt.Printf("%d Bind error:Wrong Bind Format\n", m.Chat.ID)
|
||||
bot.Send(m.Chat, "错误的格式")
|
||||
return
|
||||
}
|
||||
fmt.Println("client_id: " + tmp[0] + " client_secret" + tmp[1])
|
||||
cid := tmp[0]
|
||||
cse := tmp[1]
|
||||
bot.Send(m.Chat, "授权账户: [点击直达]("+MSGetAuthUrl(cid)+")", tb.ModeMarkdown)
|
||||
_, err := bot.Send(m.Chat, "请回复http://localhost/…… + 空格 + 别名(用于管理)", &tb.ReplyMarkup{ForceReply: true})
|
||||
if err == nil {
|
||||
UserStatus[m.Chat.ID] = USBind2
|
||||
UserCid[m.Chat.ID] = cid
|
||||
UserCSecret[m.Chat.ID] = cse
|
||||
}
|
||||
}
|
||||
func bUnBind(m *tb.Message) {
|
||||
data := QueryDataByTG(db, m.Chat.ID)
|
||||
var inlineKeys [][]tb.InlineButton
|
||||
for _, u := range data {
|
||||
inlineBtn := tb.InlineButton{
|
||||
Unique: "unbind" + u.msId,
|
||||
Text: u.other,
|
||||
Text: u.alias,
|
||||
Data: u.msId,
|
||||
}
|
||||
bot.Handle(&inlineBtn, bUnBindInlineBtn)
|
||||
@ -112,7 +138,15 @@ func bOnText(m *tb.Message) {
|
||||
bot.Send(m.Chat, "发送/bind开始绑定嗷")
|
||||
return
|
||||
}
|
||||
case USWillBind:
|
||||
case USBind1:
|
||||
{
|
||||
if !m.IsReply() {
|
||||
bot.Send(m.Chat, "请通过回复方式绑定")
|
||||
return
|
||||
}
|
||||
bBind2(m)
|
||||
}
|
||||
case USBind2:
|
||||
{
|
||||
if !m.IsReply() {
|
||||
bot.Send(m.Chat, "请通过回复方式绑定")
|
||||
@ -123,7 +157,7 @@ func bOnText(m *tb.Message) {
|
||||
return
|
||||
}
|
||||
bot.Send(m.Chat, "正在绑定中……")
|
||||
info := BindUser(m)
|
||||
info := BindUser(m, UserCid[m.Chat.ID], UserCSecret[m.Chat.ID])
|
||||
if info == "" {
|
||||
bot.Send(m.Chat, "绑定成功!")
|
||||
} else {
|
||||
|
||||
2
main.go
2
main.go
@ -90,7 +90,7 @@ func MakeHandle() {
|
||||
fmt.Println("Make Handle……")
|
||||
bot.Handle("/start", bStart)
|
||||
bot.Handle("/my", bMy)
|
||||
bot.Handle("/bind", bBind)
|
||||
bot.Handle("/bind", bBind1)
|
||||
bot.Handle("/unbind", bUnBind)
|
||||
bot.Handle("/notice", bNotice)
|
||||
bot.Handle("/help", bHelp)
|
||||
|
||||
57
mysql.go
57
mysql.go
@ -13,6 +13,9 @@ type MSData struct {
|
||||
refreshToken string
|
||||
msId string
|
||||
uptime int64
|
||||
alias string
|
||||
clientId string
|
||||
clientSecret string
|
||||
other string
|
||||
}
|
||||
|
||||
@ -40,12 +43,12 @@ func init() {
|
||||
|
||||
//update data by msId
|
||||
func UpdateData(db *sql.DB, u MSData) (bool, error) {
|
||||
sqlString := `UPDATE users set tg_id=?,refresh_token=?,uptime=?,other=? where ms_id=?`
|
||||
sqlString := `UPDATE users set tg_id=?,refresh_token=?,uptime=?,alias=?,client_id=?,client_secret=?,other=? where ms_id=?`
|
||||
stmt, err := db.Prepare(sqlString)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
res, err := stmt.Exec(u.tgId, u.refreshToken, u.uptime, u.other, u.msId)
|
||||
res, err := stmt.Exec(u.tgId, u.refreshToken, u.uptime, u.alias, u.clientId, u.clientSecret, u.other, u.msId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -56,13 +59,13 @@ func UpdateData(db *sql.DB, u MSData) (bool, error) {
|
||||
//add data
|
||||
func AddData(db *sql.DB, u MSData) (bool, error) {
|
||||
sqlString := `
|
||||
INSERT INTO users (tg_id, refresh_token,ms_id, uptime,other)
|
||||
VALUES (?,?,?,?,?)`
|
||||
INSERT INTO users (tg_id, refresh_token,ms_id, uptime,alias,client_id,client_secret,other)
|
||||
VALUES (?,?,?,?,?,?,?,?)`
|
||||
stmt, err := db.Prepare(sqlString)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = stmt.Exec(u.tgId, u.refreshToken, u.msId, u.uptime, u.other)
|
||||
_, err = stmt.Exec(u.tgId, u.refreshToken, u.msId, u.uptime, u.alias, u.clientId, u.clientSecret, u.other)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -86,51 +89,38 @@ func DelData(db *sql.DB, msId string) (bool, error) {
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
func QueryDataByMS(db *sql.DB, msId string) []MSData {
|
||||
rows, err := db.Query("select * from users where ms_id = ?", msId)
|
||||
CheckErr(err)
|
||||
func QueryData(rows *sql.Rows) []MSData {
|
||||
|
||||
var result = make([]MSData, 0)
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var (
|
||||
tgIdt, uptimet int64
|
||||
refresht, othert, msidt string
|
||||
tgIdt, uptimet int64
|
||||
refresht, othert, msidt, aliast, clientIdt, clientSet string
|
||||
)
|
||||
rows.Scan(&tgIdt, &refresht, &msidt, &uptimet, &othert)
|
||||
rows.Scan(&tgIdt, &refresht, &msidt, &uptimet, &aliast, &clientIdt, &clientSet, &othert)
|
||||
//fmt.Println(string(tgNamet) + "=>" + uptimet.Format("2006-01-02 15:04:05"))
|
||||
result = append(result, MSData{tgIdt, refresht, msidt, uptimet, othert})
|
||||
result = append(result, MSData{tgIdt, refresht, msidt, uptimet, aliast, clientIdt, clientSet, othert})
|
||||
}
|
||||
return result
|
||||
}
|
||||
func QueryDataByMS(db *sql.DB, msId string) []MSData {
|
||||
rows, err := db.Query("select * from users where ms_id = ?", msId)
|
||||
CheckErr(err)
|
||||
return QueryData(rows)
|
||||
}
|
||||
|
||||
func QueryDataAll(db *sql.DB) []MSData {
|
||||
rows, err := db.Query("select * from users ")
|
||||
CheckErr(err)
|
||||
var result = make([]MSData, 0)
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var refresht, othert, msidt string
|
||||
var tgIdt, uptimet int64
|
||||
rows.Scan(&tgIdt, &refresht, &msidt, &uptimet, &othert)
|
||||
//fmt.Println(string(tgNamet) + "=>" + uptimet.Format("2006-01-02 15:04:05"))
|
||||
result = append(result, MSData{tgIdt, refresht, msidt, uptimet, othert})
|
||||
}
|
||||
return result
|
||||
return QueryData(rows)
|
||||
}
|
||||
|
||||
//query data by tg_id
|
||||
func QueryDataByTG(db *sql.DB, tgId int64) []MSData {
|
||||
rows, err := db.Query("select * from users where tg_id = ?", tgId)
|
||||
CheckErr(err)
|
||||
var result = make([]MSData, 0)
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var refresht, othert, msidt string
|
||||
var tgIdt, uptimet int64
|
||||
rows.Scan(&tgIdt, &refresht, &msidt, &uptimet, &othert)
|
||||
result = append(result, MSData{tgIdt, refresht, msidt, uptimet, othert})
|
||||
}
|
||||
return result
|
||||
return QueryData(rows)
|
||||
}
|
||||
func CreateTB(db *sql.DB) (bool, error) {
|
||||
|
||||
@ -139,8 +129,11 @@ func CreateTB(db *sql.DB) (bool, error) {
|
||||
(
|
||||
tg_id INTEGER,
|
||||
refresh_token TEXT,
|
||||
ms_id TEXT,
|
||||
ms_id VARCHAR(255),
|
||||
uptime INTEGER,
|
||||
alias VARCHAR(255),
|
||||
client_id VARCHAR(255),
|
||||
client_secret VARCHAR(255),
|
||||
other TEXT
|
||||
);`
|
||||
_, err := db.Exec(sqltable)
|
||||
|
||||
41
outlook.go
41
outlook.go
@ -11,15 +11,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MsApiUrl string = "https://login.microsoftonline.com"
|
||||
MsGraUrl string = "https://graph.microsoft.com"
|
||||
)
|
||||
|
||||
var (
|
||||
cliId string
|
||||
redirectUri string
|
||||
scope string
|
||||
authUrl string
|
||||
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 init() {
|
||||
@ -29,22 +24,24 @@ func init() {
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Fatal error config file: %s \n", err))
|
||||
}
|
||||
authUrl = viper.GetString("auth_url")
|
||||
cliId = GetURLValue(authUrl, "client_id")
|
||||
redirectUri, _ = url.QueryUnescape(GetURLValue(authUrl, "redirect_uri"))
|
||||
scope, _ = url.QueryUnescape(GetURLValue(authUrl, "scope"))
|
||||
//refreshtoken := "xxxx"
|
||||
//fmt.Println(MSGetUserInfo(MSGetToken(refreshtoken,"user.read mail.read")))
|
||||
//code := "xxx"
|
||||
//fmt.Println(MSFirGetToken(code))
|
||||
}
|
||||
func MSGetAuthUrl(cid string) string {
|
||||
return "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=" + cid + "&response_type=code&redirect_uri=" + url.QueryEscape(redirectUri) + "&response_mode=query&scope=" + url.QueryEscape(scope)
|
||||
}
|
||||
func MSGetReAppUrl() 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)
|
||||
app_url := "https://apps.dev.microsoft.com/?deepLink=" + url.QueryEscape(deeplink)
|
||||
return app_url
|
||||
}
|
||||
|
||||
//return access_token and refresh_token
|
||||
func MSFirGetToken(code string) (access string, refresh string) {
|
||||
func MSFirGetToken(code, cid, cse string) (access string, refresh string) {
|
||||
var r http.Request
|
||||
client := &http.Client{}
|
||||
r.ParseForm()
|
||||
r.Form.Add("client_id", cliId)
|
||||
r.Form.Add("client_id", cid)
|
||||
r.Form.Add("client_secret", cse)
|
||||
r.Form.Add("grant_type", "authorization_code")
|
||||
r.Form.Add("scope", scope)
|
||||
r.Form.Add("code", code)
|
||||
@ -54,6 +51,7 @@ func MSFirGetToken(code string) (access string, refresh string) {
|
||||
resp, err := client.Do(req)
|
||||
defer resp.Body.Close()
|
||||
content, err := ioutil.ReadAll(resp.Body)
|
||||
fmt.Println(string(content))
|
||||
if err != nil {
|
||||
fmt.Println("Fatal error ")
|
||||
}
|
||||
@ -66,11 +64,12 @@ func MSFirGetToken(code string) (access string, refresh string) {
|
||||
}
|
||||
|
||||
//return access_token
|
||||
func MSGetToken(refreshtoken string) (access string) {
|
||||
func MSGetToken(refreshtoken, cid, cse string) (access string) {
|
||||
var r http.Request
|
||||
client := &http.Client{}
|
||||
r.ParseForm()
|
||||
r.Form.Add("client_id", cliId)
|
||||
r.Form.Add("client_id", cid)
|
||||
r.Form.Add("client_secret", cse)
|
||||
r.Form.Add("grant_type", "refresh_token")
|
||||
r.Form.Add("scope", scope)
|
||||
r.Form.Add("refresh_token", refreshtoken)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user