Open eyebank opened 5 years ago
Sorry for the delay @eyebank.
@crspeller Do you know if Client4.Login()
work if MFA is enabled?
You need to use Client4.LoginWithMFA()
if MFA is enabled.
@eyebank Would you be open to submitting a PR to fix this?
where can I find this Client4.LoginWithMFA()
?
@eyebank You can find it in the golang client: https://github.com/mattermost/mattermost-server/blob/master/model/client4.go#L638
@crspeller Looking at the link you provided. Where would I put the following code for the golang bot to be able to work using mfa?
Thanks!
// LoginWithMFA logs a user in with a MFA token
func (c *Client4) LoginWithMFA(loginId, password, mfaToken string) (*User, *Response) {
m := make(map[string]string)
m["login_id"] = loginId
m["password"] = password
m["token"] = mfaToken
return c.login(m)
}
func (c *Client4) login(m map[string]string) (*User, *Response) {
r, err := c.DoApiPost("/users/login", MapToJson(m))
if err != nil {
return nil, BuildErrorResponse(r, err)
}
defer closeBody(r)
c.AuthToken = r.Header.Get(HEADER_TOKEN)
c.AuthType = HEADER_BEARER
return UserFromJson(r.Body), BuildResponse(r)
}
@EbsrVlee You replace the current login function with that one. https://github.com/mattermost/mattermost-bot-sample-golang/blob/master/bot_sample.go#L99
@crspeller Thank you! I've replaced my current login function with the one above. When I attempt to run my golang bot I get the errors undefined: Client 4 undefined: User undefined: Response Makefille:15: recipe for target 'run' failed make: *** [run] Error 2
What am I missing?
Thank you again for all your help!
@EbsrVlee Would you be open on sharing the code you currently have?
@hanzei
Sure. (I have removed username/password/email from for obvious reasons)
package main
import (
"os"
"os/signal"
"regexp"
"strings"
"time"
"github.com/mattermost/mattermost-server/model"
)
const (
SAMPLE_NAME = "**ChatBot**"
USER_EMAIL = "chatbot@email.org"
USER_PASSWORD = "password"
USER_NAME = "Chatbot"
USER_FIRST = "Chatbot"
USER_LAST = "Chatbot"
TEAM_NAME = "aibot"
CHANNEL_LOG_NAME = "chat"
)
var client *model.Client4
var webSocketClient *model.WebSocketClient
var botUser *model.User
var botTeam *model.Team
var debuggingChannel *model.Channel
// Documentation for the Go driver can be found
// at https://godoc.org/github.com/mattermost/platform/model#Client
func main() {
println(SAMPLE_NAME)
SetupGracefulShutdown()
client = model.NewAPIv4Client("http://localhost:8065")
// Lets test to see if the mattermost server is up and running
MakeSureServerIsRunning()
// lets attempt to login to the Mattermost server as the bot user
// This will set the token required for all future calls
// You can get this token with client.AuthToken
LoginAsTheBotUser()
// If the bot user doesn't have the correct information lets update his profile
UpdateTheBotUserIfNeeded()
// Lets find our bot team
FindBotTeam()
// This is an important step. Lets make sure we use the botTeam
// for all future web service requests that require a team.
//client.SetTeamId(botTeam.Id)
// Lets create a bot channel for logging debug messages into
CreateBotDebuggingChannelIfNeeded()
SendMsgToDebuggingChannel("_"+SAMPLE_NAME+" has **started** running_", "")
// Lets start listening to some channels via the websocket!
webSocketClient, err := model.NewWebSocketClient4("ws://localhost:8065", client.AuthToken)
if err != nil {
println("We failed to connect to the web socket")
PrintError(err)
}
webSocketClient.Listen()
go func() {
for {
select {
case resp := <-webSocketClient.EventChannel:
HandleWebSocketResponse(resp)
}
}
}()
// You can block forever with
select {}
}
func MakeSureServerIsRunning() {
if props, resp := client.GetOldClientConfig(""); resp.Error != nil {
println("There was a problem pinging the Mattermost server. Are you sure it's running?")
PrintError(resp.Error)
os.Exit(1)
} else {
println("Server detected and is running version " + props["Version"])
}
}
// LoginWithMFA logs a user in with a MFA token
func (c *Client4) LoginWithMFA(loginId, password, mfaToken string) (*User, *Response) {
m := make(map[string]string)
m["login_id"] = Chatbot
m["password"] = password
m["token"] = 123456
return c.login(m)
}
func (c *Client4) login(m map[string]string) (*User, *Response) {
r, err := c.DoApiPost("/users/login", MapToJson(m))
if err != nil {
return nil, BuildErrorResponse(r, err)
}
defer closeBody(r)
c.AuthToken = r.Header.Get(HEADER_TOKEN)
c.AuthType = HEADER_BEARER
return UserFromJson(r.Body), BuildResponse(r)
}
//func LoginAsTheBotUser() {
// if user, resp := client.Login(USER_EMAIL, USER_PASSWORD); resp.Error != nil {
// println("There was a problem logging into the Mattermost server. Are you sure ran the setup steps from the README.md?")
// PrintError(resp.Error)
// os.Exit(1)
// } else {
// botUser = user
// }
//}
func UpdateTheBotUserIfNeeded() {
if botUser.FirstName != USER_FIRST || botUser.LastName != USER_LAST || botUser.Username != USER_NAME {
botUser.FirstName = USER_FIRST
botUser.LastName = USER_LAST
botUser.Username = USER_NAME
if user, resp := client.UpdateUser(botUser); resp.Error != nil {
println("We failed to update the Sample Bot user")
PrintError(resp.Error)
os.Exit(1)
} else {
botUser = user
println("Looks like this might be the first run so we've updated the bots account settings")
}
}
}
func FindBotTeam() {
if team, resp := client.GetTeamByName(TEAM_NAME, ""); resp.Error != nil {
println("We failed to get the initial load")
println("or we do not appear to be a member of the team '" + TEAM_NAME + "'")
PrintError(resp.Error)
os.Exit(1)
} else {
botTeam = team
}
}
func CreateBotDebuggingChannelIfNeeded() {
if rchannel, resp := client.GetChannelByName(CHANNEL_LOG_NAME, botTeam.Id, ""); resp.Error != nil {
println("We failed to get the channels")
PrintError(resp.Error)
} else {
debuggingChannel = rchannel
return
}
// Looks like we need to create the logging channel
channel := &model.Channel{}
channel.Name = CHANNEL_LOG_NAME
channel.DisplayName = "Town"
channel.Purpose = "This is used as a test channel for logging bot debug messages"
channel.Type = model.CHANNEL_OPEN
channel.TeamId = botTeam.Id
if rchannel, resp := client.CreateChannel(channel); resp.Error != nil {
println("We failed to create the channel " + CHANNEL_LOG_NAME)
PrintError(resp.Error)
} else {
debuggingChannel = rchannel
println("Looks like this might be the first run so we've created the channel " + CHANNEL_LOG_NAME)
}
}
func SendMsgToDebuggingChannel(msg string, replyToId string) {
post := &model.Post{}
post.ChannelId = debuggingChannel.Id
post.Message = msg
post.RootId = replyToId
if _, resp := client.CreatePost(post); resp.Error != nil {
println("We failed to send a message to the logging channel")
PrintError(resp.Error)
}
}
func HandleWebSocketResponse(event *model.WebSocketEvent) {
HandleMsgFromDebuggingChannel(event)
}
func HandleMsgFromDebuggingChannel(event *model.WebSocketEvent) {
// If this isn't the debugging channel then lets ingore it
if event.Broadcast.ChannelId != debuggingChannel.Id {
return
}
// Lets only reponded to messaged posted events
if event.Event != model.WEBSOCKET_EVENT_POSTED {
return
}
println("responding to debugging channel msg")
post := model.PostFromJson(strings.NewReader(event.Data["post"].(string)))
if post != nil {
// ignore my events
if post.UserId == botUser.Id {
return
}
// if you see any word matching 'alive' then respond
if matched, _ := regexp.MatchString(`(?:^|\W)alive(?:$|\W)`, post.Message); matched {
SendMsgToDebuggingChannel("Yes I'm running", post.Id)
return
}
// if you see any word matching 'up' then respond
if matched, _ := regexp.MatchString(`(?:^|\W)up(?:$|\W)`, post.Message); matched {
SendMsgToDebuggingChannel("Yes I'm running", post.Id)
return
}
// if you see any word matching 'running' then respond
if matched, _ := regexp.MatchString(`(?:^|\W)running(?:$|\W)`, post.Message); matched {
SendMsgToDebuggingChannel("Yes I'm running", post.Id)
return
}
// if you see any word matching 'hello' then respond
if matched, _ := regexp.MatchString(`(?:^|\W)hello(?:$|\W)`, post.Message); matched {
SendMsgToDebuggingChannel("Hi! How are you? :smile:", post.Id)
return
}
}
SendMsgToDebuggingChannel("I did not understand you! Please try the help command.", post.Id)
}
func PrintError(err *model.AppError) {
println("\tError Details:")
println("\t\t" + err.Message)
println("\t\t" + err.Id)
println("\t\t" + err.DetailedError)
}
func SetupGracefulShutdown() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
for _ = range c {
if webSocketClient != nil {
webSocketClient.Close()
}
SendMsgToDebuggingChannel("_"+SAMPLE_NAME+" has **stopped** running_", "")
os.Exit(0)
}
}()
}
Hey @EbsrVlee,
You have to explicitly select the packages you want to use. E.g. if you want to use the struct User
from github.com/mattermost/mattermost-server/model
, you have to select it via model.User
.
Hi @hanzei , thank you for the advice. I'm fairly new to golang. Could you give me an example of how to select it from model.user?
Thank you again.
I would advice to read and play through "A Tour of Go" first. This is a tutorial made by the Go team targeting new gophers.
Server 5.6.0.
Attempting to run golang after configuring google MFA. Startup fails. Any thoughts,