diff --git a/commands.go b/commands.go index 262c40a..29d796e 100644 --- a/commands.go +++ b/commands.go @@ -101,6 +101,10 @@ func (handler *CommandHandler) CommandMux(ce *CommandEvent) { handler.CommandPing(ce) case "logout": handler.CommandLogout(ce) + case "save-password": + handler.CommandSavePassword(ce) + case "remove-password": + handler.CommandRemovePassword(ce) case "login-matrix", "sync", "list", "open", "pm", "invite", "kick", "leave", "join", "create", "share": if !ce.User.HasSession() { ce.Reply("You're not logged in. Use the `login` command to log into Skype.") @@ -220,6 +224,10 @@ func (handler *CommandHandler) CommandLogin(ce *CommandEvent) { ce.Reply("**Usage:** `login username password`") return } + if ce.User.Conn != nil && ce.User.Conn.LoggedIn == true { + ce.Reply("You're already logged into Skype.") + return + } leavePortals(ce) if !ce.User.Connect(true) { ce.User.log.Debugln("Connect() returned false, assuming error was logged elsewhere and canceling login.") @@ -234,7 +242,7 @@ func (handler *CommandHandler) CommandLogin(ce *CommandEvent) { const cmdLogoutHelp = `logout - Logout from Skype` func (handler *CommandHandler) CommandLogout(ce *CommandEvent) { - if ce.User.Conn == nil { + if ce.User.Conn == nil || ce.User.Conn.LoggedIn == false { ce.Reply("You're not logged into Skype.") return } @@ -270,11 +278,57 @@ func (handler *CommandHandler) CommandLogout(ce *CommandEvent) { } } ce.Reply("Logged out successfully.") + ce.User.Conn.LoginInfo = nil if ce.User.Conn.Refresh != nil { ce.User.Conn.Refresh <- -1 } else { leavePortals(ce) } + ret := ce.User.bridge.DB.User.GetCredentialsByMXID(ce.User.MXID, &password, &username) + if ret && password != "" { + ce.Reply("WARNING, your password is stored in database. Use command `remove-password` to remove it.") + } +} + +const cmdSavePasswordHelp = `save-password - save user password into database` + +// CommandSavePassword handles save-password command +func (handler *CommandHandler) CommandSavePassword(ce *CommandEvent) { + var ret bool + if len(ce.Args) > 0 { + ce.Reply("**Usage:** `save-password`") + return + } + + if ce.User.Conn == nil || ce.User.Conn.LoggedIn == false { + ce.Reply("You're not logged into Skype.") + return + } + + ret = ce.User.bridge.DB.User.SetCredentialsByMXID(ce.User.Conn.LoginInfo.Password, ce.User.Conn.LoginInfo.Username, ce.User.MXID) + if ret == true { + ce.Reply("Your password was successfully saved into database.") + } else { + ce.Reply("An error occurred while saving your password into database. Try it again.") + } +} + +const cmdRemovePasswordHelp = `remove-password - remove user password from database` + +// CommandRemovePassword handles remove-password command +func (handler *CommandHandler) CommandRemovePassword(ce *CommandEvent) { + var ret bool + if len(ce.Args) > 0 { + ce.Reply("**Usage:** `remove-password`") + return + } + + ret = ce.User.bridge.DB.User.SetCredentialsByMXID("", "", ce.User.MXID) + if ret == true { + ce.Reply("Your password was successfully removed from database.") + } else { + ce.Reply("An error occurred while removing your password from database. Try it again.") + } } func leavePortals(ce *CommandEvent) { @@ -334,6 +388,12 @@ func (handler *CommandHandler) CommandPing(ce *CommandEvent) { } ce.Reply("You're logged in as @" + username + ", orgid is " + orgId) } + var password string; + var username string; + ret := ce.User.bridge.DB.User.GetCredentialsByMXID(ce.User.MXID, &password, &username) + if ret && password != "" { + ce.Reply("WARNING, your password is stored in database. Use command `remove-password` to remove it.") + } } const cmdHelpHelp = `help - Prints this help` @@ -349,6 +409,8 @@ func (handler *CommandHandler) CommandHelp(ce *CommandEvent) { cmdPrefix + cmdHelpHelp, cmdPrefix + cmdLoginHelp, cmdPrefix + cmdLogoutHelp, + cmdPrefix + cmdSavePasswordHelp, + cmdPrefix + cmdRemovePasswordHelp, cmdPrefix + cmdPingHelp, //cmdPrefix + cmdLoginMatrixHelp, //cmdPrefix + cmdLogoutMatrixHelp, diff --git a/database/upgrades/2022-04-02-add-password-username.go b/database/upgrades/2022-04-02-add-password-username.go new file mode 100644 index 0000000..31c5c15 --- /dev/null +++ b/database/upgrades/2022-04-02-add-password-username.go @@ -0,0 +1,25 @@ +package upgrades + +import ( + "database/sql" +) + +func init() { + upgrades[20] = upgrade{"Add password and username column to user table.", func(tx *sql.Tx, c context) error { + if c.dialect == Postgres { + _, err := tx.Exec(`ALTER TABLE "user" ADD COLUMN password VARCHAR(255)`) + if err != nil { + return err + } + } + + if c.dialect == Postgres { + _, err := tx.Exec(`ALTER TABLE "user" ADD COLUMN username VARCHAR(255)`) + if err != nil { + return err + } + } + + return nil + }} +} diff --git a/database/upgrades/upgrades.go b/database/upgrades/upgrades.go index e224593..af54f6c 100644 --- a/database/upgrades/upgrades.go +++ b/database/upgrades/upgrades.go @@ -39,7 +39,7 @@ type upgrade struct { fn upgradeFunc } -const NumberOfUpgrades = 20 +const NumberOfUpgrades = 21 var upgrades [NumberOfUpgrades]upgrade diff --git a/database/user.go b/database/user.go index 45ac771..5673af3 100644 --- a/database/user.go +++ b/database/user.go @@ -54,6 +54,20 @@ func (uq *UserQuery) GetByJID(userID types.SkypeID) *User { return uq.New().Scan(row) } +func (uq *UserQuery) GetCredentialsByMXID(userID id.UserID, password *string, username *string) bool { + row := uq.db.QueryRow(`SELECT password, username FROM "user" WHERE mxid=$1`, userID) + if row == nil { + return false + } + err := row.Scan(password, username) + return err == nil +} + +func (uq *UserQuery) SetCredentialsByMXID(password string, username string, userID id.UserID) bool { + row := uq.db.QueryRow(`UPDATE "user" SET password=$1, username=$2 WHERE mxid=$3`, password, username, userID) + return row != nil +} + type User struct { db *Database log log.Logger diff --git a/user.go b/user.go index 3eb7650..e380e26 100644 --- a/user.go +++ b/user.go @@ -294,6 +294,27 @@ func (user *User) Connect(evenIfNoSession bool) bool { func (user *User) RestoreSession() bool { if user.Session != nil { + var password string + var username string + ret := user.bridge.DB.User.GetCredentialsByMXID(user.MXID, &password, &username) + if ret && password != "" && username != "" { + user.log.Debugln("Found password for user " + user.MXID + " in database, trying to login.") + ce := &CommandEvent{ + Bot: user.bridge.MatrixHandler.cmd.bridge.Bot, + Bridge: user.bridge.MatrixHandler.cmd.bridge, + Handler: user.bridge.MatrixHandler.cmd, + RoomID: user.GetManagementRoom(), + User: user, + } + err := user.Login(ce, username, password) + if err == nil { + user.log.Debugln("User " + username + " successfully connected.") + syncAll(user, false) + } + } else { + user.log.Debugln("An error occured while obtaining username and password for user " + user.MXID + ".") + } + //sess, err := user.Conn.RestoreWithSession(*user.Session) //if err == whatsapp.ErrAlreadyLoggedIn { // return true @@ -395,8 +416,20 @@ func (user *User) monitorSession(ce *CommandEvent) { fmt.Println("monitorSession: ", x) if x > 0 { user.SetSession(user.Conn.LoginInfo) + } else if ce.User.Conn.LoginInfo != nil { + user.log.Debugln("Session expired for user " + ce.User.Conn.LoginInfo.Username + " trying to relogin.") + err := user.Login(ce, ce.User.Conn.LoginInfo.Username, ce.User.Conn.LoginInfo.Password) + if err == nil { + user.log.Debugln("User " + ce.User.Conn.LoginInfo.Username + " successfully reconnected.") + syncAll(user, false) + } else { + user.log.Debugln("Unable to relogin user %s", ce.User.Conn.LoginInfo.Username) + ce.Reply("Session expired and relogin failed.") + close(user.Conn.Refresh) + leavePortals(ce) + } } else { - ce.Reply("Session expired") + ce.Reply("Session expired\nStore your password into database with command `save-password` to resolve this issue.") close(user.Conn.Refresh) leavePortals(ce) }