修复授权方式

This commit is contained in:
iyear 2020-03-30 22:18:09 +08:00
parent 0deaeaa2cc
commit c40e2df6fc
6 changed files with 115 additions and 93 deletions

View File

@ -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各种编译错误。
最后实在折腾不起来只好改用MySQLVPS上都是一键Win上装MySQL也折腾了半天
------
虽然自知写的垃圾但也是第一个正式的Go Project……
## License
GPLv3

View File

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

View File

@ -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 解绑账户
@ -22,14 +24,15 @@ const (
var (
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 {

View File

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

View File

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

View File

@ -13,13 +13,8 @@ import (
const (
MsApiUrl string = "https://login.microsoftonline.com"
MsGraUrl string = "https://graph.microsoft.com"
)
var (
cliId string
redirectUri string
scope string
authUrl string
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)