Skip to content

Commit

Permalink
auto login
Browse files Browse the repository at this point in the history
  • Loading branch information
halacs committed Jan 2, 2024
1 parent ec12f7c commit 0acb927
Show file tree
Hide file tree
Showing 13 changed files with 157 additions and 76 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ If all goes fine, later this repository will provide you both a GoLang SDK and a
## TODOs
* [ ] Create json output for machines. Improve documentation accordingly.
* [ ] Add retries. `status` command produces `PORT_ERROR` quite frequently while second try works fine.
* [ ] Improve token handling. Token is stored in `config.yaml` but it seems to be invalidated after a while. It should be renewed on demand.
* [x] Improve token handling. Token is stored in `config.yaml` but it seems to be invalidated after a while. It should be renewed on demand.

## Usage
```
Expand All @@ -35,6 +35,7 @@ Available Commands:
users Manages users defined in your Hörmann BiSecur gateway.
Flags:
--autologin login automatically on demand (default true)
--debug debug log level (default true)
-h, --help help for halsecur
--host string IP or host name or the Hörmann BiSecure gateway
Expand Down
47 changes: 47 additions & 0 deletions cli/cmd/autologin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package cmd

import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"time"
)

func loginRequired(name string) bool {
loginRequiredCommands := []string{StatusCmdUse, SetStateCmdUse}

for _, i := range loginRequiredCommands {
if name == i {
return true
}
}

return false
}

func autoLogin(cmd *cobra.Command, args []string) error {
if !loginRequired(cmd.Use) {
log.Debugf("Login not required. Don't need to auto login.")
return nil
}

autoLogin := viper.GetBool(ArgNameAutoLogin)
if !autoLogin {
log.Debugf("Auto login is disabled.")
return nil
}

lastLoginTimeStamp := viper.GetInt64(ArgNameLastLoginTimeStamp)
t := time.UnixMicro(lastLoginTimeStamp)

if t.Add(TokenExpirationTime).Before(time.Now()) {
log.Infof("Token expired. Logging in...")
err := loginCmdFunc()
if err != nil {
return fmt.Errorf("failed to auto login. %v", err)
}
}

log.Debugf("Token is still valid.")
return nil
}
21 changes: 20 additions & 1 deletion cli/cmd/consts.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
package cmd

import "time"

const (
devicePortName = "devicePort"
ArgNameToken = "token"
ArgNameUsername = "username"
ArgNamePassword = "password"
ArgNameHost = "host"
ArgNamePort = "port"
ArgNameDeviceMac = "mac"
ArgNameDebug = "debug"
ArgNameAutoLogin = "autologin"
ArgNameLastLoginTimeStamp = "lastLogin"
devicePortName = "devicePort"
UsersCmdUse = "users"
StatusCmdUse = "status"
SetStateCmdUse = "set-state"
GroupsCmdName = "groups"
LoginCmdName = "login"
LogoutCmdName = "logout"
PingCmdName = "ping"
TokenExpirationTime = time.Minute * 5
)
8 changes: 4 additions & 4 deletions cli/cmd/discover.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ func init() {
)

discoverCmd := &cobra.Command{
Use: "discover",
Short: "Discover Hörmann BiSecur gateways on the local network",
Long: ``,
PreRun: toggleDebug,
Use: "discover",
Short: "Discover Hörmann BiSecur gateways on the local network",
Long: ``,
PreRunE: preRunFuncs,
Run: func(cmd *cobra.Command, args []string) {
err := discover(discoveryTime)
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions cli/cmd/getName.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (

func init() {
getNameCmd := &cobra.Command{
Use: "get-name",
Short: "Queries the name of the Hörmann BiSecur gateway",
Long: ``,
PreRun: toggleDebug,
Use: "get-name",
Short: "Queries the name of the Hörmann BiSecur gateway",
Long: ``,
PreRunE: preRunFuncs,
Run: func(cmd *cobra.Command, args []string) {
deviceMac := viper.GetString(ArgNameDeviceMac)
host := viper.GetString(ArgNameHost)
Expand Down
8 changes: 4 additions & 4 deletions cli/cmd/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (

func init() {
groupsCmd := &cobra.Command{
Use: "groups",
Short: "Manages users defined in your Hörmann BiSecur gateway.",
Long: ``,
PreRun: toggleDebug,
Use: GroupsCmdName,
Short: "Manages users defined in your Hörmann BiSecur gateway.",
Long: ``,
PreRunE: preRunFuncs,
Run: func(cmd *cobra.Command, args []string) {
// TODO implement query user list and rights, add and delete user, password change of an already existing user

Expand Down
66 changes: 38 additions & 28 deletions cli/cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,61 @@ package cmd
import (
"bisecure/cli"
"bisecure/sdk"
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"os"

"github.com/spf13/cobra"
"time"
)

func init() {
loginCmd := &cobra.Command{
Use: "login",
Short: "",
Long: ``,
PreRun: toggleDebug,
Use: LoginCmdName,
Short: "",
Long: ``,
PreRunE: preRunFuncs,
Run: func(cmd *cobra.Command, args []string) {
deviceMac := viper.GetString(ArgNameDeviceMac)
host := viper.GetString(ArgNameHost)
port := viper.GetInt(ArgNamePort)
username := viper.GetString(ArgNameUsername)
password := viper.GetString(ArgNamePassword)

mac, err := cli.ParesMacString(deviceMac)
if err != nil {
log.Fatalf("%v", err)
os.Exit(1)
}

token, err := login(localMac, mac, host, port, username, password)
err := loginCmdFunc()
if err != nil {
log.Fatalf("%v", err)
os.Exit(2)
}

log.Infof("Token: 0x%X", token)

// Store token in persistent config
viper.Set(ArgNameToken, token)
err = viper.WriteConfig()
if err != nil {
log.Errorf("Failed to save new configuration. %v", err)
}
},
}

rootCmd.AddCommand(loginCmd)
}

func loginCmdFunc() error {
deviceMac := viper.GetString(ArgNameDeviceMac)
host := viper.GetString(ArgNameHost)
port := viper.GetInt(ArgNamePort)
username := viper.GetString(ArgNameUsername)
password := viper.GetString(ArgNamePassword)

mac, err := cli.ParesMacString(deviceMac)
if err != nil {
return err
}

token, err := login(localMac, mac, host, port, username, password)
if err != nil {
return err
}

log.Infof("Token: 0x%X", token)

// Store token in persistent config
viper.Set(ArgNameToken, token)
viper.Set(ArgNameLastLoginTimeStamp, time.Now().UnixMicro())
err = viper.WriteConfig()
if err != nil {
return fmt.Errorf("failed to save new configuration. %v", err)
}

return nil
}

func login(localMac [6]byte, mac [6]byte, host string, port int, username string, password string) (uint32, error) {
client := sdk.NewClient(log, localMac, mac, host, port, 0)
err := client.Open()
Expand Down
8 changes: 4 additions & 4 deletions cli/cmd/logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import (

func init() {
logoutCmd := &cobra.Command{
Use: "logout",
Short: "",
Long: ``,
PreRun: toggleDebug,
Use: LogoutCmdName,
Short: "",
Long: ``,
PreRunE: preRunFuncs,
Run: func(cmd *cobra.Command, args []string) {
deviceMac := viper.GetString(ArgNameDeviceMac)
host := viper.GetString(ArgNameHost)
Expand Down
8 changes: 4 additions & 4 deletions cli/cmd/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ func init() {
)

pingCmd := &cobra.Command{
Use: "ping",
Short: "Check if your Hörmann BiSecur gateway is reachable or not.",
Long: ``,
PreRun: toggleDebug,
Use: PingCmdName,
Short: "Check if your Hörmann BiSecur gateway is reachable or not.",
Long: ``,
PreRunE: preRunFuncs,
Run: func(cmd *cobra.Command, args []string) {
deviceMac := viper.GetString(ArgNameDeviceMac)
host := viper.GetString(ArgNameHost)
Expand Down
32 changes: 18 additions & 14 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"fmt"
"github.com/spf13/viper"
"os"

Expand All @@ -15,10 +16,10 @@ var (

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "halsecur",
Short: "Application to manage your Hörmann BiSecur gateway without the central cloud directly on your LAN.",
Long: ``,
PreRun: toggleDebug,
Use: "halsecur",
Short: "Application to manage your Hörmann BiSecur gateway without the central cloud directly on your LAN.",
Long: ``,
PreRunE: preRunFuncs,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
Expand All @@ -33,16 +34,6 @@ func Execute() {
}
}

const (
ArgNameToken = "token"
ArgNameUsername = "username"
ArgNamePassword = "password"
ArgNameHost = "host"
ArgNamePort = "port"
ArgNameDeviceMac = "mac"
ArgNameDebug = "debug"
)

func init() {
log = newLogger()

Expand All @@ -54,6 +45,7 @@ func init() {
password string
deviceMac string
debug bool
autoLogin bool
)

rootCmd.PersistentFlags().Uint32Var(&token, ArgNameToken, 0x0, "Valid authentication token")
Expand All @@ -63,6 +55,7 @@ func init() {
rootCmd.PersistentFlags().IntVar(&port, ArgNamePort, 4000, "")
rootCmd.PersistentFlags().StringVar(&deviceMac, ArgNameDeviceMac, "", "MAC address of the Hörmann BiSecur gateway")
rootCmd.PersistentFlags().BoolVar(&debug, ArgNameDebug, true, "debug log level")
rootCmd.PersistentFlags().BoolVar(&autoLogin, ArgNameAutoLogin, true, "login automatically on demand")

viper.SetConfigName("config") // name of config file (without extension)
viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
Expand All @@ -85,6 +78,17 @@ func init() {
}
}

func preRunFuncs(cmd *cobra.Command, args []string) error {
toggleDebug(cmd, args)

err := autoLogin(cmd, args)
if err != nil {
return fmt.Errorf("failed to auto login. %v", err)
}

return nil
}

func toggleDebug(cmd *cobra.Command, args []string) {
debug := viper.GetBool(ArgNameDebug)
if debug {
Expand Down
8 changes: 4 additions & 4 deletions cli/cmd/setState.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ func init() {
var devicePort int

setStateCmd := &cobra.Command{
Use: "set-state",
Short: "Open or close a door connected to your Hörmann BiSecur gateway.",
Long: ``,
PreRun: toggleDebug,
Use: SetStateCmdUse,
Short: "Open or close a door connected to your Hörmann BiSecur gateway.",
Long: ``,
PreRunE: preRunFuncs,
Run: func(cmd *cobra.Command, args []string) {
deviceMac := viper.GetString(ArgNameDeviceMac)
host := viper.GetString(ArgNameHost)
Expand Down
8 changes: 4 additions & 4 deletions cli/cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ func init() {
var devicePort int

statusCmd := &cobra.Command{
Use: "status",
Short: "Queries the status (open/closed/etc) of your door.",
Long: ``,
PreRun: toggleDebug,
Use: StatusCmdUse,
Short: "Queries the status (open/closed/etc) of your door.",
Long: ``,
PreRunE: preRunFuncs,
Run: func(cmd *cobra.Command, args []string) {
deviceMac := viper.GetString(ArgNameDeviceMac)
host := viper.GetString(ArgNameHost)
Expand Down
8 changes: 4 additions & 4 deletions cli/cmd/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (

func init() {
usersCmd := &cobra.Command{
Use: "users",
Short: "Manages users defined in your Hörmann BiSecur gateway.",
Long: ``,
PreRun: toggleDebug,
Use: UsersCmdUse,
Short: "Manages users defined in your Hörmann BiSecur gateway.",
Long: ``,
PreRunE: preRunFuncs,
Run: func(cmd *cobra.Command, args []string) {
// TODO implement query user list and rights, add and delete user, password change of an already existing user

Expand Down

0 comments on commit 0acb927

Please sign in to comment.