diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml old mode 100644 new mode 100755 diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml old mode 100644 new mode 100755 diff --git a/.github/workflows/gosec.yml b/.github/workflows/gosec.yml old mode 100644 new mode 100755 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.idea/.gitignore b/.idea/.gitignore old mode 100644 new mode 100755 diff --git a/.idea/bisecure.iml b/.idea/bisecure.iml old mode 100644 new mode 100755 diff --git a/.idea/modules.xml b/.idea/modules.xml old mode 100644 new mode 100755 diff --git a/.idea/vcs.xml b/.idea/vcs.xml old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 3858a20..2838c4c --- a/README.md +++ b/README.md @@ -2,12 +2,13 @@ # Hörmann BiSecur Gateway CLI client and GoLang SDK -Goal is to create a fully fledged replacement client after Hörmann stated end of life of their cloud and android application. +This command line client (CLI) and software developer kit (SDK) is able to communicate with your Hörmann BiSecur Gateway directly via IP connection. -If all goes fine, later this repository will provide you both a GoLang SDK and a CLI client you can use to -- open and close your door -- manage users -- etc. +You can discover gateways available on your LAN or you can specify its IP address directly if you are not in the same Layer 2 segment / broadcast domain to discover them. The letter is can be important if you can reach your home network via a Layer 3 VPN connection. + +Never ever let your gateway reachable from the public internet, for example, with help of port forward! This gateway is very poor on security to do so! I strongly suggest to keep your gateway reachable only on your secure LAN network. For more details please refer to the sutdy of sec-consult in the links section. + +Hörmann officially supported this gateway version until end of 2023 / beginning of 2024. ![gateway image](gateway.webp) @@ -59,6 +60,29 @@ Flags: Use "halsecur [command] --help" for more information about a command. ``` +### Config file +`config.yaml` needs to be placed next to the application binary in the same directoy. + +Below you can find an example configuration file works for me. + +Please replace at least `host`, `mac`, `username` and `password` values to match with your setup. + +As far as I know port if always 4000 so most probably it never need to be changed. + +```bash +autologin: true +debug: false +host: 192.168.3.232 +json: false +lastlogin: 1711743671911748 +mac: 54:10:EC:85:28:BB +password: ADD-YOUR-PASSWORD +port: 4000 +token: 0 +username: app +``` + + ### Ping ```bash $ dist/halsecur ping --host 192.168.3.232 --mac 54:10:EC:85:28:BB --count 3 --delay 1000 @@ -69,36 +93,33 @@ INFO[2024-01-31T21:12:48+01:00] Response 3 of 3 received in 63 ms ### Get device name ```bash -$ dist/halsecur get-name -INFO[2024-01-31T21:08:47+01:00] Received name: BiSecur Gateway +$ ./dist/halsecur get-name +INFO[2024-03-29T21:20:03+01:00] Success name="BiSecur Gateway" ``` ### Login ```bash -$ ./dist/halsecur login --host 192.168.3.232 --mac 54:10:EC:85:28:BB --password Gabor123456789. --username app -INFO[2024-01-31T21:09:40+01:00] Token: 0x3AC29326 -INFO[2024-01-31T21:09:40+01:00] Success +$ ./dist/halsecur login ``` ### Get users ```bash $ ./dist/halsecur users list -INFO[2024-01-31T21:56:53+01:00] [{"id":0,"name":"admin","isAdmin":true,"Groups":[]},{"id":1,"name":"app","isAdmin":false,"Groups":[0]}] +INFO[2024-03-29T21:20:36+01:00] Success users="[{\"id\":0,\"name\":\"admin\",\"isAdmin\":true,\"Groups\":[]},{\"id\":1,\"name\":\"app\",\"isAdmin\":false,\"Groups\":[0]}]" ``` ### Get groups ```bash $ ./dist/halsecur groups list -INFO[2024-02-01T17:35:32+01:00] [{"id":0,"name":"garazs","ports":[{"typeName":"IMPULS","id":0,"type":1}]}] +INFO[2024-03-29T21:20:55+01:00] [{"id":0,"name":"garazs","ports":[{"typeName":"IMPULS","id":0,"type":1}]}] ``` ### Get door status ```bash $ ./dist/halsecur status --devicePort 0 -INFO[2024-02-01T17:34:22+01:00] Token expired. Logging in... -INFO[2024-02-01T17:34:22+01:00] Token: 0xA0A67B43 -INFO[2024-02-01T17:34:24+01:00] Transition: {"StateInPercent":0,"DesiredStateInPercent":0,"Error":false,"AutoClose":false,"DriveTime":0,"Gk":257,"Hcp":{"PositionOpen":false,"PositionClose":true,"OptionRelais":false,"LightBarrier":false,"Error":false,"DrivingToClose":false,"Driving":false,"HalfOpened":false,"ForecastLeadTime":false,"Learned":true,"NotReferenced":false},"Exst":"AAAAAAAAAAA=","Time":"2024-02-01T17:34:24.794359108+01:00"} - +INFO[2024-03-29T21:21:11+01:00] Token expired. Logging in... +INFO[2024-03-29T21:21:11+01:00] Token: 0x53972BFB +INFO[2024-03-29T21:21:12+01:00] Success status="{\"StateInPercent\":0,\"DesiredStateInPercent\":0,\"Error\":false,\"AutoClose\":false,\"DriveTime\":0,\"Gk\":257,\"Hcp\":{\"PositionOpen\":false,\"PositionClose\":true,\"OptionRelais\":false,\"LightBarrier\":false,\"Error\":false,\"DrivingToClose\":false,\"Driving\":false,\"HalfOpened\":false,\"ForecastLeadTime\":false,\"Learned\":true,\"NotReferenced\":false},\"Exst\":\"AAAAAAAAAAA=\",\"Time\":\"2024-03-29T21:21:12.719862537+01:00\"}" ``` ### Open/close door @@ -106,42 +127,21 @@ Door is fully closed. Start to open it: ```bash $ ./dist/halsecur set-state --devicePort 0 -DEBU[2023-12-26T21:04:33+01:00] Connecting to 192.168.3.232:4000 -DEBU[2023-12-26T21:04:33+01:00] Request: SrcMAC=0x000000000009, DstMAC=0x5410EC8528BB, BodyLength=0x0, packet=[Tag=0x1, Token=0x7974DB57, CommandID=0x33 (0x33), payload=[SetState], Checksum=0x0, isResponse=false], Checksum=0x0, isResponse: false -DEBU[2023-12-26T21:04:33+01:00] Request bytes: 303030303030303030303039353431304543383532384242303030423031373937344442353733333030464635444331 -DEBU[2023-12-26T21:04:34+01:00] Length of received bytes: 76 -DEBU[2023-12-26T21:04:34+01:00] Response bytes: 5410EC8528BB00000000000600190100000000F0000000040101020200000000000000001483 -DEBU[2023-12-26T21:04:34+01:00] Received TC: SrcMAC=0x5410EC8528BB, DstMAC=0x000000000006, BodyLength=0x19, packet=[Tag=0x1, Token=0x0, CommandID=0x70 (0xF0), payload=[HmGetTransitionResponse[StateInPercent: 0, DesiredStateInPerced: 0, Error: false, AutoClose: false, DriveTime: 4, Gk: 257, Hcp: HCP[PositionOpen: false, PositionClose: true, OptionRelais: false, LightBarrier: false, Error: false, DrivingToClose: false, Driving: false, HalfOpened: false, ForecastLeadTime: false, Learned: true, NotReferenced: false], Exst: [0 0 0 0 0 0 0 0], Time: 2023-12-26 21:04:34.436781605 +0100 CET m=+0.770579311]], Checksum=0x14, isResponse=true], Checksum=0x83, isResponse: true -DEBU[2023-12-26T21:04:34+01:00] Set State response: SrcMAC=0x5410EC8528BB, DstMAC=0x000000000006, BodyLength=0x19, packet=[Tag=0x1, Token=0x0, CommandID=0x70 (0xF0), payload=[HmGetTransitionResponse[StateInPercent: 0, DesiredStateInPerced: 0, Error: false, AutoClose: false, DriveTime: 4, Gk: 257, Hcp: HCP[PositionOpen: false, PositionClose: true, OptionRelais: false, LightBarrier: false, Error: false, DrivingToClose: false, Driving: false, HalfOpened: false, ForecastLeadTime: false, Learned: true, NotReferenced: false], Exst: [0 0 0 0 0 0 0 0], Time: 2023-12-26 21:04:34.436781605 +0100 CET m=+0.770579311]], Checksum=0x14, isResponse=true], Checksum=0x83, isResponse: true -INFO[2023-12-26T21:04:34+01:00] Done +INFO[2024-03-29T21:22:00+01:00] Success ``` Door is opening. Stop it in a half-open position: ```Bash $ ./dist/halsecur set-state --devicePort 0 -DEBU[2023-12-26T21:04:43+01:00] Connecting to 192.168.3.232:4000 -DEBU[2023-12-26T21:04:43+01:00] Request: SrcMAC=0x000000000009, DstMAC=0x5410EC8528BB, BodyLength=0x0, packet=[Tag=0x1, Token=0x7974DB57, CommandID=0x33 (0x33), payload=[SetState], Checksum=0x0, isResponse=false], Checksum=0x0, isResponse: false -DEBU[2023-12-26T21:04:43+01:00] Request bytes: 303030303030303030303039353431304543383532384242303030423031373937344442353733333030464635444331 -DEBU[2023-12-26T21:04:43+01:00] Length of received bytes: 76 -DEBU[2023-12-26T21:04:43+01:00] Response bytes: 5410EC8528BB00000000000600190100000000F00000000401014C0200000000000000005EAD -DEBU[2023-12-26T21:04:43+01:00] Received TC: SrcMAC=0x5410EC8528BB, DstMAC=0x000000000006, BodyLength=0x19, packet=[Tag=0x1, Token=0x0, CommandID=0x70 (0xF0), payload=[HmGetTransitionResponse[StateInPercent: 0, DesiredStateInPerced: 0, Error: false, AutoClose: false, DriveTime: 4, Gk: 257, Hcp: HCP[PositionOpen: false, PositionClose: false, OptionRelais: true, LightBarrier: true, Error: false, DrivingToClose: false, Driving: true, HalfOpened: false, ForecastLeadTime: false, Learned: true, NotReferenced: false], Exst: [0 0 0 0 0 0 0 0], Time: 2023-12-26 21:04:43.979174613 +0100 CET m=+0.807240492]], Checksum=0x5E, isResponse=true], Checksum=0xAD, isResponse: true -DEBU[2023-12-26T21:04:43+01:00] Set State response: SrcMAC=0x5410EC8528BB, DstMAC=0x000000000006, BodyLength=0x19, packet=[Tag=0x1, Token=0x0, CommandID=0x70 (0xF0), payload=[HmGetTransitionResponse[StateInPercent: 0, DesiredStateInPerced: 0, Error: false, AutoClose: false, DriveTime: 4, Gk: 257, Hcp: HCP[PositionOpen: false, PositionClose: false, OptionRelais: true, LightBarrier: true, Error: false, DrivingToClose: false, Driving: true, HalfOpened: false, ForecastLeadTime: false, Learned: true, NotReferenced: false], Exst: [0 0 0 0 0 0 0 0], Time: 2023-12-26 21:04:43.979174613 +0100 CET m=+0.807240492]], Checksum=0x5E, isResponse=true], Checksum=0xAD, isResponse: true -INFO[2023-12-26T21:04:43+01:00] Done +INFO[2024-03-29T21:22:07+01:00] Success ``` Door is half-opened. Close it back: ```Bash $ ./dist/halsecur set-state --devicePort 0 -DEBU[2023-12-26T21:04:47+01:00] Connecting to 192.168.3.232:4000 -DEBU[2023-12-26T21:04:47+01:00] Request: SrcMAC=0x000000000009, DstMAC=0x5410EC8528BB, BodyLength=0x0, packet=[Tag=0x1, Token=0x7974DB57, CommandID=0x33 (0x33), payload=[SetState], Checksum=0x0, isResponse=false], Checksum=0x0, isResponse: false -DEBU[2023-12-26T21:04:47+01:00] Request bytes: 303030303030303030303039353431304543383532384242303030423031373937344442353733333030464635444331 -DEBU[2023-12-26T21:04:48+01:00] Length of received bytes: 76 -DEBU[2023-12-26T21:04:48+01:00] Response bytes: 5410EC8528BB00000000000600190100000000F00000000401010C0200000000000000001EA5 -DEBU[2023-12-26T21:04:48+01:00] Received TC: SrcMAC=0x5410EC8528BB, DstMAC=0x000000000006, BodyLength=0x19, packet=[Tag=0x1, Token=0x0, CommandID=0x70 (0xF0), payload=[HmGetTransitionResponse[StateInPercent: 0, DesiredStateInPerced: 0, Error: false, AutoClose: false, DriveTime: 4, Gk: 257, Hcp: HCP[PositionOpen: false, PositionClose: false, OptionRelais: true, LightBarrier: true, Error: false, DrivingToClose: false, Driving: false, HalfOpened: false, ForecastLeadTime: false, Learned: true, NotReferenced: false], Exst: [0 0 0 0 0 0 0 0], Time: 2023-12-26 21:04:48.329008833 +0100 CET m=+0.781378758]], Checksum=0x1E, isResponse=true], Checksum=0xA5, isResponse: true -DEBU[2023-12-26T21:04:48+01:00] Set State response: SrcMAC=0x5410EC8528BB, DstMAC=0x000000000006, BodyLength=0x19, packet=[Tag=0x1, Token=0x0, CommandID=0x70 (0xF0), payload=[HmGetTransitionResponse[StateInPercent: 0, DesiredStateInPerced: 0, Error: false, AutoClose: false, DriveTime: 4, Gk: 257, Hcp: HCP[PositionOpen: false, PositionClose: false, OptionRelais: true, LightBarrier: true, Error: false, DrivingToClose: false, Driving: false, HalfOpened: false, ForecastLeadTime: false, Learned: true, NotReferenced: false], Exst: [0 0 0 0 0 0 0 0], Time: 2023-12-26 21:04:48.329008833 +0100 CET m=+0.781378758]], Checksum=0x1E, isResponse=true], Checksum=0xA5, isResponse: true -INFO[2023-12-26T21:04:48+01:00] Done +INFO[2024-03-29T21:22:42+01:00] Success ``` ## Acknowledgement @@ -152,6 +152,14 @@ Based on the above study someone could create a [Kotlin SDK](https://github.com/ Taken into consideration that Hörmann will stop their cloud required for BiSecur Gateway usages from 2024, I asked Hörmann support to publish their protocol already leaked in above repositories, but they stated that this code is impossible to write. +## Contribution + +Please feel free to implement the missing commands in the SDK or in the CLI application. + +When you are done with it please raise a pull request. I will do my best to merge to the upstram as soon as possible. + +Whenever you raise a pull request please try to keep test coverage as high as possible and describe clearly what is the feature you have implemented and how you tested it. + ## Disclaimer **ABSOLUTELY NO WARRANTY! USE AT YOUR OWN RISK!** @@ -172,4 +180,4 @@ By using this software, you acknowledge that it was developed with the best inte ## Links - https://sec-consult.com/blog/detail/hoermann-opening-doors-for-everyone/ -- https://github.com/bisdk/sdk \ No newline at end of file +- https://github.com/bisdk/sdk diff --git a/cli/cmd/autologin.go b/cli/cmd/autologin.go old mode 100644 new mode 100755 diff --git a/cli/cmd/consts.go b/cli/cmd/consts.go old mode 100644 new mode 100755 diff --git a/cli/cmd/discover.go b/cli/cmd/discover.go old mode 100644 new mode 100755 diff --git a/cli/cmd/getName.go b/cli/cmd/getName.go old mode 100644 new mode 100755 index 350aa92..7e913f6 --- a/cli/cmd/getName.go +++ b/cli/cmd/getName.go @@ -63,7 +63,7 @@ func GetName(localMac, mac [6]byte, host string, port int, token uint32) error { return err } - log.Infof("Received name: %s", name) + log.WithField("name", name).Infof("Success") return nil } diff --git a/cli/cmd/groups.go b/cli/cmd/groups.go old mode 100644 new mode 100755 diff --git a/cli/cmd/groupsAdd.go b/cli/cmd/groupsAdd.go old mode 100644 new mode 100755 diff --git a/cli/cmd/groupsDelete.go b/cli/cmd/groupsDelete.go old mode 100644 new mode 100755 diff --git a/cli/cmd/groupsList.go b/cli/cmd/groupsList.go old mode 100644 new mode 100755 diff --git a/cli/cmd/login.go b/cli/cmd/login.go old mode 100644 new mode 100755 index 055b380..10bbf11 --- a/cli/cmd/login.go +++ b/cli/cmd/login.go @@ -23,7 +23,7 @@ func init() { os.Exit(2) } - log.Infof("Success") + log.Infof("Successful login") }, } diff --git a/cli/cmd/logout.go b/cli/cmd/logout.go old mode 100644 new mode 100755 diff --git a/cli/cmd/passwordChange.go b/cli/cmd/passwordChange.go old mode 100644 new mode 100755 diff --git a/cli/cmd/ping.go b/cli/cmd/ping.go old mode 100644 new mode 100755 diff --git a/cli/cmd/retry.go b/cli/cmd/retry.go old mode 100644 new mode 100755 diff --git a/cli/cmd/root.go b/cli/cmd/root.go old mode 100644 new mode 100755 diff --git a/cli/cmd/setState.go b/cli/cmd/setState.go old mode 100644 new mode 100755 diff --git a/cli/cmd/status.go b/cli/cmd/status.go old mode 100644 new mode 100755 index a0475a6..e96e1dd --- a/cli/cmd/status.go +++ b/cli/cmd/status.go @@ -69,7 +69,7 @@ func getStatus(localMac [6]byte, mac [6]byte, host string, port int, devicePort return err } - log.Infof("Transition: %+v", status) + log.WithField("status", status).Infof("Success") return nil } diff --git a/cli/cmd/users.go b/cli/cmd/users.go old mode 100644 new mode 100755 diff --git a/cli/cmd/usersAdd.go b/cli/cmd/usersAdd.go old mode 100644 new mode 100755 diff --git a/cli/cmd/usersList.go b/cli/cmd/usersList.go old mode 100644 new mode 100755 index f2202b8..a6ba170 --- a/cli/cmd/usersList.go +++ b/cli/cmd/usersList.go @@ -63,7 +63,7 @@ func listUsers(localMac [6]byte, mac [6]byte, host string, port int, token uint3 return err } - log.Infof("%s", users.String()) + log.WithField("users", users).Infof("Success") return nil } diff --git a/cli/cmd/usersRemove.go b/cli/cmd/usersRemove.go old mode 100644 new mode 100755 diff --git a/cli/cmd/version.go b/cli/cmd/version.go old mode 100644 new mode 100755 diff --git a/cli/utils.go b/cli/utils.go old mode 100644 new mode 100755 diff --git a/cli/utils_test.go b/cli/utils_test.go old mode 100644 new mode 100755 diff --git "a/docs/H\303\266rmann Opening Doors for everyone... - SEC Consult.pdf" "b/docs/H\303\266rmann Opening Doors for everyone... - SEC Consult.pdf" old mode 100644 new mode 100755 diff --git a/gateway.webp b/gateway.webp old mode 100644 new mode 100755 diff --git a/go.mod b/go.mod old mode 100644 new mode 100755 diff --git a/go.sum b/go.sum old mode 100644 new mode 100755 diff --git a/main.go b/main.go old mode 100644 new mode 100755 diff --git a/sdk/Client.go b/sdk/Client.go old mode 100644 new mode 100755 diff --git a/sdk/Consts.go b/sdk/Consts.go old mode 100644 new mode 100755 diff --git a/sdk/Discovery.go b/sdk/Discovery.go old mode 100644 new mode 100755 diff --git a/sdk/Discovery_test.go b/sdk/Discovery_test.go old mode 100644 new mode 100755 diff --git a/sdk/Group.go b/sdk/Group.go old mode 100644 new mode 100755 diff --git a/sdk/Group_test.go b/sdk/Group_test.go old mode 100644 new mode 100755 diff --git a/sdk/Packet.go b/sdk/Packet.go old mode 100644 new mode 100755 diff --git a/sdk/Packet_test.go b/sdk/Packet_test.go old mode 100644 new mode 100755 diff --git a/sdk/Port.go b/sdk/Port.go old mode 100644 new mode 100755 diff --git a/sdk/RealDevice_test.go b/sdk/RealDevice_test.go old mode 100644 new mode 100755 diff --git a/sdk/TransmissionContainer.go b/sdk/TransmissionContainer.go old mode 100644 new mode 100755 diff --git a/sdk/TransmissionContainer_test.go b/sdk/TransmissionContainer_test.go old mode 100644 new mode 100755 diff --git a/sdk/User.go b/sdk/User.go old mode 100644 new mode 100755 diff --git a/sdk/User_test.go b/sdk/User_test.go old mode 100644 new mode 100755 diff --git a/sdk/Values.go b/sdk/Values.go old mode 100644 new mode 100755 diff --git a/sdk/payload/AddUserReponse.go b/sdk/payload/AddUserReponse.go old mode 100644 new mode 100755 diff --git a/sdk/payload/ChangeUserPassword.go b/sdk/payload/ChangeUserPassword.go old mode 100644 new mode 100755 diff --git a/sdk/payload/Empty.go b/sdk/payload/Empty.go old mode 100644 new mode 100755 diff --git a/sdk/payload/Error.go b/sdk/payload/Error.go old mode 100644 new mode 100755 diff --git a/sdk/payload/GetMacResponse.go b/sdk/payload/GetMacResponse.go old mode 100644 new mode 100755 diff --git a/sdk/payload/GetName.go b/sdk/payload/GetName.go old mode 100644 new mode 100755 diff --git a/sdk/payload/GetNameResponse.go b/sdk/payload/GetNameResponse.go old mode 100644 new mode 100755 diff --git a/sdk/payload/GetUserRights.go b/sdk/payload/GetUserRights.go old mode 100644 new mode 100755 diff --git a/sdk/payload/GetUserRightsResponsePayload.go b/sdk/payload/GetUserRightsResponsePayload.go old mode 100644 new mode 100755 diff --git a/sdk/payload/HmGetTransition.go b/sdk/payload/HmGetTransition.go old mode 100644 new mode 100755 diff --git a/sdk/payload/HmGetTransitionResponse.go b/sdk/payload/HmGetTransitionResponse.go old mode 100644 new mode 100755 diff --git a/sdk/payload/HmGetTransitionResponse_test.go b/sdk/payload/HmGetTransitionResponse_test.go old mode 100644 new mode 100755 diff --git a/sdk/payload/Jcmp.go b/sdk/payload/Jcmp.go old mode 100644 new mode 100755 diff --git a/sdk/payload/Login.go b/sdk/payload/Login.go old mode 100644 new mode 100755 diff --git a/sdk/payload/LoginResponse.go b/sdk/payload/LoginResponse.go old mode 100644 new mode 100755 diff --git a/sdk/payload/MockPayload.go b/sdk/payload/MockPayload.go old mode 100644 new mode 100755 diff --git a/sdk/payload/Payload.go b/sdk/payload/Payload.go old mode 100644 new mode 100755 diff --git a/sdk/payload/PayloadInterface.go b/sdk/payload/PayloadInterface.go old mode 100644 new mode 100755 diff --git a/sdk/payload/RemoveUser.go b/sdk/payload/RemoveUser.go old mode 100644 new mode 100755 diff --git a/sdk/payload/RemoveUserResponse.go b/sdk/payload/RemoveUserResponse.go old mode 100644 new mode 100755 diff --git a/sdk/payload/SetState.go b/sdk/payload/SetState.go old mode 100644 new mode 100755 diff --git a/sdk/payload/SetUserRightsPayload.go b/sdk/payload/SetUserRightsPayload.go old mode 100644 new mode 100755 diff --git a/sdk/payload/SetUserRightsResponsePayload.go b/sdk/payload/SetUserRightsResponsePayload.go old mode 100644 new mode 100755 diff --git a/sdk/payload/hcp/Hcp.go b/sdk/payload/hcp/Hcp.go old mode 100644 new mode 100755