mirror of
https://dev.narayana.im/narayana/telegabber.git
synced 2026-08-04 19:57:07 +00:00
Login Wizard
This commit is contained in:
parent
0368b8cad8
commit
85846346d1
7 changed files with 315 additions and 58 deletions
|
|
@ -278,7 +278,7 @@ func PropertyType(key string) byte {
|
||||||
case "timezone":
|
case "timezone":
|
||||||
return PropertyTypeString
|
return PropertyTypeString
|
||||||
case "keeponline", "rawmessages", "asciiarrows", "oobmode", "carbons", "hideids",
|
case "keeponline", "rawmessages", "asciiarrows", "oobmode", "carbons", "hideids",
|
||||||
"receipts", "nativeedits", "ignoregroupdeletions":
|
"receipts", "nativeedits", "ignoregroupdeletions":
|
||||||
return PropertyTypeBool
|
return PropertyTypeBool
|
||||||
}
|
}
|
||||||
return PropertyTypeUnknown
|
return PropertyTypeUnknown
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,10 @@ type Client struct {
|
||||||
cache *cache.Cache
|
cache *cache.Cache
|
||||||
online bool
|
online bool
|
||||||
|
|
||||||
|
loginWizard *loginWizardMetadata
|
||||||
|
|
||||||
|
lastAuthorizationStateType string
|
||||||
|
|
||||||
outbox map[string]string
|
outbox map[string]string
|
||||||
editOutbox map[string]string
|
editOutbox map[string]string
|
||||||
|
|
||||||
|
|
@ -75,6 +79,15 @@ type clientLocks struct {
|
||||||
|
|
||||||
authorizerReadLock sync.Mutex
|
authorizerReadLock sync.Mutex
|
||||||
authorizerWriteLock sync.Mutex
|
authorizerWriteLock sync.Mutex
|
||||||
|
|
||||||
|
loginWizardReadLock sync.Mutex
|
||||||
|
loginWizardWriteLock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type loginWizardMetadata struct {
|
||||||
|
nextStage chan string
|
||||||
|
chanBusy bool
|
||||||
|
commandSent bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient instantiates a Telegram App
|
// NewClient instantiates a Telegram App
|
||||||
|
|
|
||||||
|
|
@ -51,22 +51,22 @@ var permissionsMember = client.ChatPermissions{
|
||||||
var permissionsReadonly = client.ChatPermissions{}
|
var permissionsReadonly = client.ChatPermissions{}
|
||||||
|
|
||||||
var transportCommands = map[string]command{
|
var transportCommands = map[string]command{
|
||||||
"help": command{0, []string{}, "help", nil},
|
"help": command{0, []string{}, "help", false, nil},
|
||||||
"login": command{1, []string{"phone"}, "sign in", nil},
|
"login": command{1, []string{"phone"}, "sign in", false, nil},
|
||||||
"logout": command{0, []string{}, "sign out", nil},
|
"logout": command{0, []string{}, "sign out", true, nil},
|
||||||
"cancelauth": command{0, []string{}, "quit the signin wizard", nil},
|
"cancelauth": command{0, []string{}, "quit the signin wizard", false, nil},
|
||||||
"code": command{1, []string{"xxxxx"}, "check one-time code", nil},
|
"code": command{1, []string{"xxxxx"}, "check one-time code", false, nil},
|
||||||
"password": command{1, []string{"********"}, "check 2fa password", nil},
|
"password": command{1, []string{"********"}, "check 2fa password", false, nil},
|
||||||
"setusername": command{0, []string{"@username"}, "update @username", nil},
|
"setusername": command{0, []string{"@username"}, "update @username", true, nil},
|
||||||
"setname": command{1, []string{"first", "last"}, "update name", nil},
|
"setname": command{1, []string{"first", "last"}, "update name", true, nil},
|
||||||
"setbio": command{0, []string{"Lorem ipsum"}, "update about", nil},
|
"setbio": command{0, []string{"Lorem ipsum"}, "update about", true, nil},
|
||||||
"setpassword": command{0, []string{"old", "new"}, "set or remove password", nil},
|
"setpassword": command{0, []string{"old", "new"}, "set or remove password", true, nil},
|
||||||
"config": command{0, []string{"param", "value"}, "view or update configuration options", nil},
|
"config": command{0, []string{"param", "value"}, "view or update configuration options", false, nil},
|
||||||
"report": command{2, []string{"chat", "comment"}, "report a chat by id or @username", nil},
|
"report": command{2, []string{"chat", "comment"}, "report a chat by id or @username", true, nil},
|
||||||
"add": command{1, []string{"@username"}, "add @username to your chat list", nil},
|
"add": command{1, []string{"@username"}, "add @username to your chat list", true, nil},
|
||||||
"join": command{1, []string{"https://t.me/invite_link"}, "join to chat via invite link or @publicname", nil},
|
"join": command{1, []string{"https://t.me/invite_link"}, "join to chat via invite link or @publicname", true, nil},
|
||||||
"supergroup": command{1, []string{"title", "description"}, "create new supergroup «title» with «description»", nil},
|
"supergroup": command{1, []string{"title", "description"}, "create new supergroup «title» with «description»", true, nil},
|
||||||
"channel": command{1, []string{"title", "description"}, "create new channel «title» with «description»", nil},
|
"channel": command{1, []string{"title", "description"}, "create new channel «title» with «description»", true, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
var notForGroups = []ChatType{ChatTypeBasicGroup, ChatTypeSupergroup, ChatTypeChannel}
|
var notForGroups = []ChatType{ChatTypeBasicGroup, ChatTypeSupergroup, ChatTypeChannel}
|
||||||
|
|
@ -75,37 +75,37 @@ var notForPMAndBasic = []ChatType{ChatTypePrivate, ChatTypeSecret, ChatTypeBasic
|
||||||
var onlyForSecret = []ChatType{ChatTypePrivate, ChatTypeBasicGroup, ChatTypeSupergroup, ChatTypeChannel}
|
var onlyForSecret = []ChatType{ChatTypePrivate, ChatTypeBasicGroup, ChatTypeSupergroup, ChatTypeChannel}
|
||||||
|
|
||||||
var chatCommands = map[string]command{
|
var chatCommands = map[string]command{
|
||||||
"help": command{0, []string{}, "help", nil},
|
"help": command{0, []string{}, "help", false, nil},
|
||||||
"d": command{0, []string{"n"}, "delete your last message(s)", nil},
|
"d": command{0, []string{"n"}, "delete your last message(s)", true, nil},
|
||||||
"s": command{1, []string{"edited message"}, "edit your last message", nil},
|
"s": command{1, []string{"edited message"}, "edit your last message", true, nil},
|
||||||
"silent": command{1, []string{"message"}, "send a message without sound", nil},
|
"silent": command{1, []string{"message"}, "send a message without sound", true, nil},
|
||||||
"schedule": command{2, []string{"{online | 2006-01-02T15:04:05 | 15:04:05}", "message"}, "schedules a message either to timestamp or to whenever the user goes online", nil},
|
"schedule": command{2, []string{"{online | 2006-01-02T15:04:05 | 15:04:05}", "message"}, "schedules a message either to timestamp or to whenever the user goes online", true, nil},
|
||||||
"forward": command{2, []string{"message_id", "target_chat"}, "forwards a message", nil},
|
"forward": command{2, []string{"message_id", "target_chat"}, "forwards a message", true, nil},
|
||||||
"vcard": command{0, []string{}, "print vCard as text", nil},
|
"vcard": command{0, []string{}, "print vCard as text", true, nil},
|
||||||
"add": command{1, []string{"@username"}, "add @username to your chat list", nil},
|
"add": command{1, []string{"@username"}, "add @username to your chat list", true, nil},
|
||||||
"join": command{1, []string{"https://t.me/invite_link"}, "join to chat via invite link or @publicname", nil},
|
"join": command{1, []string{"https://t.me/invite_link"}, "join to chat via invite link or @publicname", true, nil},
|
||||||
"group": command{1, []string{"title"}, "create groupchat «title» with current user", ¬ForGroups},
|
"group": command{1, []string{"title"}, "create groupchat «title» with current user", true, ¬ForGroups},
|
||||||
"supergroup": command{1, []string{"title", "description"}, "create new supergroup «title» with «description»", nil},
|
"supergroup": command{1, []string{"title", "description"}, "create new supergroup «title» with «description»", true, nil},
|
||||||
"channel": command{1, []string{"title", "description"}, "create new channel «title» with «description»", nil},
|
"channel": command{1, []string{"title", "description"}, "create new channel «title» with «description»", true, nil},
|
||||||
"secret": command{0, []string{}, "create secretchat with current user", ¬ForGroups},
|
"secret": command{0, []string{}, "create secretchat with current user", true, ¬ForGroups},
|
||||||
"search": command{0, []string{"string", "[limit]"}, "search <string> in current chat", nil},
|
"search": command{0, []string{"string", "[limit]"}, "search <string> in current chat", true, nil},
|
||||||
"history": command{0, []string{"limit"}, "get last [limit] messages from current chat", nil},
|
"history": command{0, []string{"limit"}, "get last [limit] messages from current chat", true, nil},
|
||||||
"block": command{0, []string{}, "blacklist current user", ¬ForGroups},
|
"block": command{0, []string{}, "blacklist current user", true, ¬ForGroups},
|
||||||
"unblock": command{0, []string{}, "unblacklist current user", ¬ForGroups},
|
"unblock": command{0, []string{}, "unblacklist current user", true, ¬ForGroups},
|
||||||
"invite": command{1, []string{"id or @username"}, "add user to current chat", ¬ForPM},
|
"invite": command{1, []string{"id or @username"}, "add user to current chat", true, ¬ForPM},
|
||||||
"link": command{0, []string{}, "get invite link for current chat", ¬ForPM},
|
"link": command{0, []string{}, "get invite link for current chat", true, ¬ForPM},
|
||||||
"kick": command{1, []string{"id or @username"}, "remove user from current chat", ¬ForPM},
|
"kick": command{1, []string{"id or @username"}, "remove user from current chat", true, ¬ForPM},
|
||||||
"mute": command{0, []string{"id or @username", "hours"}, "mute the whole chat or a user in current chat", ¬ForPMAndBasic},
|
"mute": command{0, []string{"id or @username", "hours"}, "mute the whole chat or a user in current chat", true, ¬ForPMAndBasic},
|
||||||
"unmute": command{0, []string{"id or @username"}, "unmute the whole chat or a user in the current chat", ¬ForPMAndBasic},
|
"unmute": command{0, []string{"id or @username"}, "unmute the whole chat or a user in the current chat", true, ¬ForPMAndBasic},
|
||||||
"ban": command{1, []string{"id or @username", "hours"}, "restrict @username from current chat for [hours] or forever", ¬ForPM},
|
"ban": command{1, []string{"id or @username", "hours"}, "restrict @username from current chat for [hours] or forever", true, ¬ForPM},
|
||||||
"unban": command{1, []string{"id or @username"}, "unbans @username in current chat (and devotes from admins)", ¬ForPM},
|
"unban": command{1, []string{"id or @username"}, "unbans @username in current chat (and devotes from admins)", true, ¬ForPM},
|
||||||
"promote": command{1, []string{"id or @username", "title"}, "promote user to admin in current chat", ¬ForPM},
|
"promote": command{1, []string{"id or @username", "title"}, "promote user to admin in current chat", true, ¬ForPM},
|
||||||
"leave": command{0, []string{}, "leave current chat", ¬ForPM},
|
"leave": command{0, []string{}, "leave current chat", true, ¬ForPM},
|
||||||
"leave!": command{0, []string{}, "leave current chat (for owners)", ¬ForPM},
|
"leave!": command{0, []string{}, "leave current chat (for owners)", true, ¬ForPM},
|
||||||
"ttl": command{0, []string{"seconds"}, "set secret chat messages TTL before self-destroying", &onlyForSecret},
|
"ttl": command{0, []string{"seconds"}, "set secret chat messages TTL before self-destroying", true, &onlyForSecret},
|
||||||
"close": command{0, []string{}, "close current secret chat", &onlyForSecret},
|
"close": command{0, []string{}, "close current secret chat", true, &onlyForSecret},
|
||||||
"delete": command{0, []string{}, "delete current chat from chat list", nil},
|
"delete": command{0, []string{}, "delete current chat from chat list", true, nil},
|
||||||
"members": command{0, []string{"query"}, "search members [by optional query] in current chat (requires admin rights)", nil},
|
"members": command{0, []string{"query"}, "search members [by optional query] in current chat (requires admin rights)", true, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
var transportConfigurationOptions = map[string]configurationOption{
|
var transportConfigurationOptions = map[string]configurationOption{
|
||||||
|
|
@ -125,6 +125,7 @@ type command struct {
|
||||||
RequiredArgs int
|
RequiredArgs int
|
||||||
Arguments []string
|
Arguments []string
|
||||||
Description string
|
Description string
|
||||||
|
LoginOnly bool
|
||||||
NotFor *[]ChatType
|
NotFor *[]ChatType
|
||||||
}
|
}
|
||||||
type configurationOption struct {
|
type configurationOption struct {
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ func (c *Client) Connect(resource string) error {
|
||||||
tdlibClient, err := client.NewClient(c.authorizer, c.options...)
|
tdlibClient, err := client.NewClient(c.authorizer, c.options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.locks.authorizationReady.Unlock()
|
c.locks.authorizationReady.Unlock()
|
||||||
|
c.wizardStageOrPrompt("cancel", "")
|
||||||
return errors.Wrap(err, "Couldn't initialize a Telegram client instance")
|
return errors.Wrap(err, "Couldn't initialize a Telegram client instance")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,6 +138,8 @@ func (c *Client) Connect(resource string) error {
|
||||||
// stage 3: if a client is succesfully created, AuthorizationStateReady is already reached
|
// stage 3: if a client is succesfully created, AuthorizationStateReady is already reached
|
||||||
log.Warn("Authorization successful!")
|
log.Warn("Authorization successful!")
|
||||||
|
|
||||||
|
c.wizardStageOrPrompt("success", "")
|
||||||
|
|
||||||
c.me, err = c.client.GetMe()
|
c.me, err = c.client.GetMe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Could not retrieve me info")
|
log.Error("Could not retrieve me info")
|
||||||
|
|
@ -255,6 +258,8 @@ func (c *Client) interactor() {
|
||||||
log.Infof("Telegram authorization state: %#v", stateType)
|
log.Infof("Telegram authorization state: %#v", stateType)
|
||||||
log.Debugf("%#v", state)
|
log.Debugf("%#v", state)
|
||||||
|
|
||||||
|
c.lastAuthorizationStateType = stateType
|
||||||
|
|
||||||
switch stateType {
|
switch stateType {
|
||||||
// stage 0: set login
|
// stage 0: set login
|
||||||
case client.TypeAuthorizationStateWaitPhoneNumber:
|
case client.TypeAuthorizationStateWaitPhoneNumber:
|
||||||
|
|
@ -262,12 +267,12 @@ func (c *Client) interactor() {
|
||||||
if c.Session.Login != "" {
|
if c.Session.Login != "" {
|
||||||
c.authorizer.PhoneNumber <- c.Session.Login
|
c.authorizer.PhoneNumber <- c.Session.Login
|
||||||
} else {
|
} else {
|
||||||
gateway.SendServiceMessage(c.jid, "Please, enter your Telegram login via /login 12345", c.xmpp)
|
c.wizardStageOrPrompt("login", "Please, enter your Telegram login via /login 12345, or use the Login Wizard via Ad-Hoc commands")
|
||||||
}
|
}
|
||||||
// stage 1: wait for auth code
|
// stage 1: wait for auth code
|
||||||
case client.TypeAuthorizationStateWaitCode:
|
case client.TypeAuthorizationStateWaitCode:
|
||||||
log.Warn("Waiting for authorization code...")
|
log.Warn("Waiting for authorization code...")
|
||||||
gateway.SendServiceMessage(c.jid, "Please, enter authorization code via /code 12345", c.xmpp)
|
c.wizardStageOrPrompt("code", "Please, enter authorization code via /code 12345")
|
||||||
// stage 1b: wait for registration
|
// stage 1b: wait for registration
|
||||||
case client.TypeAuthorizationStateWaitRegistration:
|
case client.TypeAuthorizationStateWaitRegistration:
|
||||||
log.Warn("Waiting for full name...")
|
log.Warn("Waiting for full name...")
|
||||||
|
|
@ -275,7 +280,7 @@ func (c *Client) interactor() {
|
||||||
// stage 2: wait for 2fa
|
// stage 2: wait for 2fa
|
||||||
case client.TypeAuthorizationStateWaitPassword:
|
case client.TypeAuthorizationStateWaitPassword:
|
||||||
log.Warn("Waiting for 2FA password...")
|
log.Warn("Waiting for 2FA password...")
|
||||||
gateway.SendServiceMessage(c.jid, "Please, enter 2FA passphrase via /password 12345", c.xmpp)
|
c.wizardStageOrPrompt("password", "Please, enter 2FA passphrase via /password 12345")
|
||||||
}
|
}
|
||||||
c.locks.authorizerReadLock.Unlock()
|
c.locks.authorizerReadLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
@ -294,6 +299,7 @@ func (c *Client) forceClose() {
|
||||||
func (c *Client) close() {
|
func (c *Client) close() {
|
||||||
c.locks.authorizerWriteLock.Lock()
|
c.locks.authorizerWriteLock.Lock()
|
||||||
if c.authorizer != nil && !c.authorizer.isClosed {
|
if c.authorizer != nil && !c.authorizer.isClosed {
|
||||||
|
log.Debug("Closing authorizer")
|
||||||
c.authorizer.Close()
|
c.authorizer.Close()
|
||||||
}
|
}
|
||||||
c.locks.authorizerWriteLock.Unlock()
|
c.locks.authorizerWriteLock.Unlock()
|
||||||
|
|
@ -308,6 +314,7 @@ func (c *Client) close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) cancelAuth() {
|
func (c *Client) cancelAuth() {
|
||||||
|
c.StopLoginWizard()
|
||||||
c.close()
|
c.close()
|
||||||
c.Session.Login = ""
|
c.Session.Login = ""
|
||||||
}
|
}
|
||||||
|
|
|
||||||
82
telegram/loginwizard.go
Normal file
82
telegram/loginwizard.go
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
package telegram
|
||||||
|
|
||||||
|
import (
|
||||||
|
"dev.narayana.im/narayana/telegabber/xmpp/gateway"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/zelenin/go-tdlib/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StartLoginWizard initiates a loginWizard object
|
||||||
|
func (c *Client) StartLoginWizard(inCommand bool) {
|
||||||
|
if c.loginWizard == nil {
|
||||||
|
c.loginWizard = &loginWizardMetadata{
|
||||||
|
nextStage: make(chan string, 1),
|
||||||
|
commandSent: inCommand,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.loginWizard.commandSent = inCommand
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopLoginWizard safely destroys the loginWizard object
|
||||||
|
func (c *Client) StopLoginWizard() {
|
||||||
|
c.locks.loginWizardReadLock.Lock()
|
||||||
|
c.locks.loginWizardWriteLock.Lock()
|
||||||
|
if c.loginWizard != nil {
|
||||||
|
close(c.loginWizard.nextStage)
|
||||||
|
c.loginWizard = nil
|
||||||
|
}
|
||||||
|
c.locks.loginWizardReadLock.Unlock()
|
||||||
|
c.locks.loginWizardWriteLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLoginWizardNextStage waits for the next stage from the channel
|
||||||
|
func (c *Client) GetLoginWizardNextStage() string {
|
||||||
|
c.locks.loginWizardReadLock.Lock()
|
||||||
|
defer c.locks.loginWizardReadLock.Unlock()
|
||||||
|
|
||||||
|
if c.loginWizard != nil {
|
||||||
|
if c.loginWizard.commandSent {
|
||||||
|
log.Debugf("waiting for nextStage...")
|
||||||
|
nextStage := <-c.loginWizard.nextStage
|
||||||
|
c.loginWizard.commandSent = false
|
||||||
|
c.loginWizard.chanBusy = false
|
||||||
|
log.Debugf("yielded stage %v", nextStage)
|
||||||
|
return nextStage
|
||||||
|
} else {
|
||||||
|
if c.lastAuthorizationStateType == client.TypeAuthorizationStateWaitPhoneNumber ||
|
||||||
|
c.lastAuthorizationStateType == client.TypeAuthorizationStateClosing ||
|
||||||
|
c.Session.Login == "" {
|
||||||
|
return "login"
|
||||||
|
}
|
||||||
|
switch c.lastAuthorizationStateType {
|
||||||
|
case client.TypeAuthorizationStateWaitCode:
|
||||||
|
return "code"
|
||||||
|
case client.TypeAuthorizationStateWaitPassword:
|
||||||
|
return "password"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) wizardStageOrPrompt(stage, message string) {
|
||||||
|
c.locks.loginWizardWriteLock.Lock()
|
||||||
|
if c.loginWizard == nil {
|
||||||
|
c.locks.loginWizardWriteLock.Unlock()
|
||||||
|
if message != "" {
|
||||||
|
gateway.SendServiceMessage(c.jid, message, c.xmpp)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !c.loginWizard.chanBusy {
|
||||||
|
log.Debugf("writing wizard stage %v", stage)
|
||||||
|
c.loginWizard.nextStage <- stage
|
||||||
|
} else {
|
||||||
|
log.Warn("Skipping stage %v, wizard cannot keep up", stage)
|
||||||
|
}
|
||||||
|
c.loginWizard.chanBusy = true
|
||||||
|
c.locks.loginWizardWriteLock.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -679,25 +679,41 @@ func handleGetDiscoItems(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoItems) {
|
||||||
|
|
||||||
log.Debugf("discoItems: %#v", di)
|
log.Debugf("discoItems: %#v", di)
|
||||||
|
|
||||||
_, ok := toToID(iq.To)
|
_, toOk := toToID(iq.To)
|
||||||
if di.Node == gateway.NSCommand {
|
if di.Node == gateway.NSCommand {
|
||||||
answer.Payload = di
|
answer.Payload = di
|
||||||
|
|
||||||
chatType, chatTypeErr := getTelegramChatType(iq.From, iq.To)
|
chatType, chatTypeErr := getTelegramChatType(iq.From, iq.To)
|
||||||
|
|
||||||
var cmdType telegram.CommandType
|
var cmdType telegram.CommandType
|
||||||
if ok {
|
if toOk {
|
||||||
cmdType = telegram.CommandTypeChat
|
cmdType = telegram.CommandTypeChat
|
||||||
} else {
|
} else {
|
||||||
cmdType = telegram.CommandTypeTransport
|
cmdType = telegram.CommandTypeTransport
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isOnline bool
|
||||||
|
bare, _, ok := gateway.SplitJID(iq.From)
|
||||||
|
if ok {
|
||||||
|
session, ok := sessions[bare]
|
||||||
|
if ok {
|
||||||
|
isOnline = session.Online()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(toOk || isOnline) {
|
||||||
|
di.AddItem(iq.To, "loginwizard", "Login Wizard")
|
||||||
|
}
|
||||||
|
|
||||||
commands := telegram.GetCommands(cmdType)
|
commands := telegram.GetCommands(cmdType)
|
||||||
for _, name := range telegram.SortedCommandKeys(commands) {
|
for _, name := range telegram.SortedCommandKeys(commands) {
|
||||||
command := commands[name]
|
command := commands[name]
|
||||||
if chatTypeErr == nil && !telegram.IsCommandForChatType(command, chatType) {
|
if chatTypeErr == nil && !telegram.IsCommandForChatType(command, chatType) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if !isOnline && command.LoginOnly {
|
||||||
|
continue
|
||||||
|
}
|
||||||
di.AddItem(iq.To, name, telegram.CommandToHelpString(name, command))
|
di.AddItem(iq.To, name, telegram.CommandToHelpString(name, command))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -851,7 +867,13 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer gateway.ResumableSend(component, answer)
|
cancelSend := false
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if !cancelSend {
|
||||||
|
gateway.ResumableSend(component, answer)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
log.Debugf("command: %#v", command)
|
log.Debugf("command: %#v", command)
|
||||||
|
|
||||||
|
|
@ -938,12 +960,20 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
|
||||||
}
|
}
|
||||||
|
|
||||||
answer.Payload = &stanza.Command{
|
answer.Payload = &stanza.Command{
|
||||||
SessionId: command.Node,
|
SessionId: command.Node,
|
||||||
Node: command.Node,
|
Node: command.Node,
|
||||||
Status: stanza.CommandStatusCompleted,
|
Status: stanza.CommandStatusCompleted,
|
||||||
CommandElements: elements,
|
CommandElements: elements,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if command.Node == "loginwizard" {
|
||||||
|
var session *telegram.Client
|
||||||
|
answer.Payload, cancelSend, session = loginWizardPayload(bare, form, resource)
|
||||||
|
|
||||||
|
log.Debugf("immediate loginwizard payload: %#v", answer.Payload)
|
||||||
|
if cancelSend {
|
||||||
|
go sendLoginWizardResponse(component, answer, session)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// just for the case the client messed the order somehow
|
// just for the case the client messed the order somehow
|
||||||
sort.Slice(form.Fields, func(i int, j int) bool {
|
sort.Slice(form.Fields, func(i int, j int) bool {
|
||||||
|
|
@ -1072,10 +1102,24 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
|
||||||
CommandElements: []stanza.CommandElement{&form},
|
CommandElements: []stanza.CommandElement{&form},
|
||||||
}
|
}
|
||||||
log.Debugf("form: %#v", form)
|
log.Debugf("form: %#v", form)
|
||||||
|
} else if command.Node == "loginwizard" {
|
||||||
|
var session *telegram.Client
|
||||||
|
answer.Payload, cancelSend, session = loginWizardPayload(bare, nil, resource)
|
||||||
|
|
||||||
|
log.Debugf("immediate loginwizard payload: %#v", answer.Payload)
|
||||||
|
if cancelSend {
|
||||||
|
go sendLoginWizardResponse(component, answer, session)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cmdString = "/" + command.Node
|
cmdString = "/" + command.Node
|
||||||
}
|
}
|
||||||
} else if command.Action == stanza.CommandActionCancel {
|
} else if command.Action == stanza.CommandActionCancel {
|
||||||
|
if command.Node == "loginwizard" {
|
||||||
|
session, ok := sessions[bare]
|
||||||
|
if ok {
|
||||||
|
session.ProcessTransportCommand("/cancelauth", resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
answer.Payload = &stanza.Command{
|
answer.Payload = &stanza.Command{
|
||||||
SessionId: command.Node,
|
SessionId: command.Node,
|
||||||
Node: command.Node,
|
Node: command.Node,
|
||||||
|
|
@ -1119,7 +1163,7 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("command response: %#v", answer.Payload)
|
log.Debugf("command response: %#v %v", answer.Payload, cancelSend)
|
||||||
}
|
}
|
||||||
|
|
||||||
func iqAnswerSetError(answer *stanza.IQ, payload *extensions.QueryRegister, code int) {
|
func iqAnswerSetError(answer *stanza.IQ, payload *extensions.QueryRegister, code int) {
|
||||||
|
|
|
||||||
110
xmpp/loginwizard.go
Normal file
110
xmpp/loginwizard.go
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
package xmpp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"dev.narayana.im/narayana/telegabber/telegram"
|
||||||
|
"dev.narayana.im/narayana/telegabber/xmpp/gateway"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"gosrc.io/xmpp"
|
||||||
|
"gosrc.io/xmpp/stanza"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setCommandPayloadError(payload *stanza.Command, err string) {
|
||||||
|
note := stanza.Note{
|
||||||
|
Text: err,
|
||||||
|
Type: stanza.CommandNoteTypeErr,
|
||||||
|
}
|
||||||
|
payload.Status = stanza.CommandStatusCompleted
|
||||||
|
payload.CommandElements = append(payload.CommandElements, ¬e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loginWizardPayload(bare string, requestForm *stanza.Form, resource string) (payload *stanza.Command, cancelSend bool, returnSession *telegram.Client) {
|
||||||
|
payload = &stanza.Command{
|
||||||
|
SessionId: "loginwizard",
|
||||||
|
Node: "loginwizard",
|
||||||
|
}
|
||||||
|
|
||||||
|
session, ok := sessions[bare]
|
||||||
|
if ok {
|
||||||
|
returnSession = session
|
||||||
|
|
||||||
|
if requestForm == nil {
|
||||||
|
session.StartLoginWizard(false)
|
||||||
|
cancelSend = true
|
||||||
|
} else {
|
||||||
|
if len(requestForm.Fields) != 1 {
|
||||||
|
setCommandPayloadError(payload, "Hey, don't tinker with the form!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
field := requestForm.Fields[0]
|
||||||
|
if field != nil {
|
||||||
|
if len(field.ValuesList) < 1 {
|
||||||
|
setCommandPayloadError(payload, "No value")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch field.Var {
|
||||||
|
case "login", "code", "password":
|
||||||
|
default:
|
||||||
|
setCommandPayloadError(payload, "Unknown field")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
session.StartLoginWizard(true)
|
||||||
|
response, success := session.ProcessTransportCommand(fmt.Sprintf("/%v %v", field.Var, field.ValuesList[0]), resource)
|
||||||
|
if !success {
|
||||||
|
setCommandPayloadError(payload, response)
|
||||||
|
session.StopLoginWizard()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelSend = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setCommandPayloadError(payload, fmt.Sprintf("Session is not initialized, add the transport (%v) to contacts first", gateway.Jid.Bare()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendLoginWizardResponse(component *xmpp.Component, answer *stanza.IQ, session *telegram.Client) {
|
||||||
|
payload := &stanza.Command{
|
||||||
|
SessionId: "loginwizard",
|
||||||
|
Node: "loginwizard",
|
||||||
|
}
|
||||||
|
|
||||||
|
nextStage := "login"
|
||||||
|
if session != nil {
|
||||||
|
nextStage = session.GetLoginWizardNextStage()
|
||||||
|
}
|
||||||
|
log.Debugf("nextStage: %v", nextStage)
|
||||||
|
|
||||||
|
if nextStage == "cancel" {
|
||||||
|
setCommandPayloadError(payload, "Cancelled")
|
||||||
|
session.StopLoginWizard()
|
||||||
|
} else if nextStage == "success" {
|
||||||
|
payload.Status = stanza.CommandStatusCompleted
|
||||||
|
session.StopLoginWizard()
|
||||||
|
} else {
|
||||||
|
required := ""
|
||||||
|
form := stanza.Form{
|
||||||
|
Type: stanza.FormTypeForm,
|
||||||
|
Title: "Login Wizard",
|
||||||
|
Fields: []*stanza.Field{
|
||||||
|
&stanza.Field{
|
||||||
|
Var: nextStage,
|
||||||
|
Label: nextStage,
|
||||||
|
Required: &required,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
payload.Status = stanza.CommandStatusExecuting
|
||||||
|
payload.CommandElements = append(payload.CommandElements, &form)
|
||||||
|
}
|
||||||
|
|
||||||
|
answer.Payload = payload
|
||||||
|
|
||||||
|
gateway.ResumableSend(component, answer)
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue