diff --git a/hs100 b/hs100 new file mode 100644 index 0000000..cbea306 Binary files /dev/null and b/hs100 differ diff --git a/main.go b/main.go new file mode 100644 index 0000000..f1548bf --- /dev/null +++ b/main.go @@ -0,0 +1,108 @@ +package main + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "log" + "net" + "os" +) + +var debug = false + +func encrypt(s string) []byte { + key := byte(171) + buf := new(bytes.Buffer) + binary.Write(buf, binary.BigEndian, uint32(len(s))) + + // Iterate through the string and apply the XOR cipher + for i := 0; i < len(s); i++ { + a := key ^ s[i] + key = a + buf.WriteByte(a) + } + + return buf.Bytes() +} + +func decrypt(ciphertext []byte) string { + if len(ciphertext) < 4 { + return "" + } + payload := ciphertext[4:] + key := byte(171) + result := make([]byte, len(payload)) + + for i, b := range payload { + a := key ^ b + key = b + result[i] = a + } + return string(result) +} + +func sendPayload(ip, command string) (string, error) { + conn, err := net.Dial("tcp", ip+":9999") + if err != nil { + return "", fmt.Errorf("failed to connect: %w", err) + } + defer conn.Close() + + encPayload := encrypt(command) + if _, err := conn.Write(encPayload); err != nil { + return "", fmt.Errorf("failed to send data: %w", err) + } + + response, err := io.ReadAll(conn) + if err != nil { + return "", fmt.Errorf("failed to get response: %w", err) + } + + decryptResponse := decrypt(response[4:]) + return decryptResponse, nil +} + +func validateIp(ip string) bool { + return net.ParseIP(ip) != nil +} + +func main() { + nea := "Not enough arguments provided" + if len(os.Args) > 1 { + userIp := os.Args[1] + var cmd string + if validateIp(userIp) { + if len(os.Args) > 2 { + switch os.Args[2] { + case "on", "1": + cmd = `{"system":{"set_relay_state":{"state":1}}}` + case "off", "0": + cmd = `{"system":{"set_relay_state":{"state":0}}}` + default: + fmt.Println("Invalid argument") + os.Exit(1) + } + } else { + fmt.Println(nea) + os.Exit(1) + } + response, err := sendPayload(userIp, cmd) + if err != nil { + log.Fatal(err) + } + if debug { + fmt.Printf("response: %s\n", response) + } + } else { + fmt.Println("Invalid IP provided") + os.Exit(1) + } + } else { + fmt.Println(nea) + fmt.Printf("Usage %s {ip} {on|off}\n", os.Args[0]) + os.Exit(1) + } + os.Exit(0) +} diff --git a/notes b/notes new file mode 100644 index 0000000..12c6257 --- /dev/null +++ b/notes @@ -0,0 +1 @@ +compile command: CGO_ENABLED=0 go build -o hs100 -ldflags="-s -w" main.go && upx -9 hs100 \ No newline at end of file diff --git a/tplink-smarthome-commands.txt b/tplink-smarthome-commands.txt new file mode 100644 index 0000000..f2bbc89 --- /dev/null +++ b/tplink-smarthome-commands.txt @@ -0,0 +1,163 @@ +TP-Link Smart Home Protocol Command List +======================================== +(for TP-Link HS100 and HS110) + +System Commands +======================================== +Get System Info (Software & Hardware Versions, MAC, deviceID, hwID etc.) +{"system":{"get_sysinfo":null}} + +Reboot +{"system":{"reboot":{"delay":1}}} + +Reset (To Factory Settings) +{"system":{"reset":{"delay":1}}} + +Turn On +{"system":{"set_relay_state":{"state":1}}} + +Turn Off +{"system":{"set_relay_state":{"state":0}}} + +Turn On Device LED (Night mode) +{"system":{"set_led_off":{"off":0}}} + +Turn Off Device LED (Night mode) +{"system":{"set_led_off":{"off":1}}} + +Set Device Alias +{"system":{"set_dev_alias":{"alias":"supercool plug"}}} + +Set MAC Address +{"system":{"set_mac_addr":{"mac":"50-C7-BF-01-02-03"}}} + +Set Device ID +{"system":{"set_device_id":{"deviceId":"0123456789ABCDEF0123456789ABCDEF01234567"}}} + +Set Hardware ID +{"system":{"set_hw_id":{"hwId":"0123456789ABCDEF0123456789ABCDEF"}}} + +Set Location +{"system":{"set_dev_location":{"longitude":6.9582814,"latitude":50.9412784}}} + +Perform uBoot Bootloader Check +{"system":{"test_check_uboot":null}} + +Get Device Icon +{"system":{"get_dev_icon":null}} + +Set Device Icon +{"system":{"set_dev_icon":{"icon":"xxxx","hash":"ABCD"}}} + +Set Test Mode (command only accepted coming from IP 192.168.1.100) +{"system":{"set_test_mode":{"enable":1}}} + +Download Firmware from URL +{"system":{"download_firmware":{"url":"http://...."}}} + +Get Download State +{"system":{"get_download_state":{}}} + +Flash Downloaded Firmware +{"system":{"flash_firmware":{}}} + +Check Config +{"system":{"check_new_config":null}} + + +WLAN Commands +======================================== +Scan for list of available APs +{"netif":{"get_scaninfo":{"refresh":1}}} + +Connect to AP with given SSID and Password +{"netif":{"set_stainfo":{"ssid":"WiFi","password":"secret","key_type":3}}} + + +Cloud Commands +======================================== +Get Cloud Info (Server, Username, Connection Status) +{"cnCloud":{"get_info":null}} + +Get Firmware List from Cloud Server +{"cnCloud":{"get_intl_fw_list":{}}} + +Set Server URL +{"cnCloud":{"set_server_url":{"server":"devs.tplinkcloud.com"}}} + +Connect with Cloud username & Password +{"cnCloud":{"bind":{"username":"your@email.com", "password":"secret"}}} + +Unregister Device from Cloud Account +{"cnCloud":{"unbind":null}} + + +Time Commands +======================================== +Get Time +{"time":{"get_time":null}} + +Get Timezone +{"time":{"get_timezone":null}} + +Set Timezone +{"time":{"set_timezone":{"year":2016,"month":1,"mday":1,"hour":10,"min":10,"sec":10,"index":42}}} + +Schedule Commands +(action to perform regularly on given weekdays) +======================================== +Get Next Scheduled Action +{"schedule":{"get_next_action":null}} + +Get Schedule Rules List +{"schedule":{"get_rules":null}} + +Add New Schedule Rule +{"schedule":{"add_rule":{"stime_opt":0,"wday":[1,0,0,1,1,0,0],"smin":1014,"enable":1,"repeat":1,"etime_opt":-1,"name":"lights on","eact":-1,"month":0,"sact":1,"year":0,"longitude":0,"day":0,"force":0,"latitude":0,"emin":0},"set_overall_enable":{"enable":1}}} + +Edit Schedule Rule with given ID +{"schedule":{"edit_rule":{"stime_opt":0,"wday":[1,0,0,1,1,0,0],"smin":1014,"enable":1,"repeat":1,"etime_opt":-1,"id":"4B44932DFC09780B554A740BC1798CBC","name":"lights on","eact":-1,"month":0,"sact":1,"year":0,"longitude":0,"day":0,"force":0,"latitude":0,"emin":0}}} + +Delete Schedule Rule with given ID +{"schedule":{"delete_rule":{"id":"4B44932DFC09780B554A740BC1798CBC"}}} + +Delete All Schedule Rules and Erase Statistics +{"schedule":{"delete_all_rules":null,"erase_runtime_stat":null}} + + +Countdown Rule Commands +(action to perform after number of seconds) +======================================== +Get Rule (only one allowed) +{"count_down":{"get_rules":null}} + +Add New Countdown Rule +{"count_down":{"add_rule":{"enable":1,"delay":1800,"act":1,"name":"turn on"}}} + +Edit Countdown Rule with given ID +{"count_down":{"edit_rule":{"enable":1,"id":"7C90311A1CD3227F25C6001D88F7FC13","delay":1800,"act":1,"name":"turn on"}}} + +Delete Countdown Rule with given ID +{"count_down":{"delete_rule":{"id":"7C90311A1CD3227F25C6001D88F7FC13"}}} + +Delete All Coundown Rules +{"count_down":{"delete_all_rules":null}} + + +Anti-Theft Rule Commands (aka Away Mode) +(period of time during which device will be randomly turned on and off to deter thieves) +======================================== +Get Anti-Theft Rules List +{"anti_theft":{"get_rules":null}} + +Add New Anti-Theft Rule +{"anti_theft":{"add_rule":{"stime_opt":0,"wday":[0,0,0,1,0,1,0],"smin":987,"enable":1,"frequency":5,"repeat":1,"etime_opt":0,"duration":2,"name":"test","lastfor":1,"month":0,"year":0,"longitude":0,"day":0,"latitude":0,"force":0,"emin":1047},"set_overall_enable":1}} + +Edit Anti-Theft Rule with given ID +{"anti_theft":{"edit_rule":{"stime_opt":0,"wday":[0,0,0,1,0,1,0],"smin":987,"enable":1,"frequency":5,"repeat":1,"etime_opt":0,"id":"E36B1F4466B135C1FD481F0B4BFC9C30","duration":2,"name":"test","lastfor":1,"month":0,"year":0,"longitude":0,"day":0,"latitude":0,"force":0,"emin":1047},"set_overall_enable":1}} + +Delete Anti-Theft Rule with given ID +{"anti_theft":{"delete_rule":{"id":"E36B1F4466B135C1FD481F0B4BFC9C30"}}} + +Delete All Anti-Theft Rules +"anti_theft":{"delete_all_rules":null}}