|
| 1 | +#!/usr/bin/env python |
| 2 | +# -*- coding: UTF-8 -*- |
| 3 | + |
| 4 | +import base64 |
| 5 | +import json |
| 6 | +import sys |
| 7 | +from urllib.parse import unquote |
| 8 | + |
| 9 | +import requests |
| 10 | +import rsa |
| 11 | + |
| 12 | + |
| 13 | +# usage |
| 14 | +# need to install packages rsa and requests |
| 15 | +# pip install requests |
| 16 | +# pip install rsa |
| 17 | +# |
| 18 | +# python mipcc.py admin password url data |
| 19 | +# python mipcc.py admin password http://192.168.2.89:80 '{"method":"do","preset":{"goto_preset": {"id": "1"}}}' |
| 20 | +# |
| 21 | +# data example: |
| 22 | +# PTZ to preset position {"method":"do","preset":{"goto_preset": {"id": "1"}}} |
| 23 | +# PTZ by coord {"method":"do","motor":{"move":{"x_coord":"10","y_coord":"0"}}} |
| 24 | +# PTZ horizontal by step {"method":"do","motor":{"movestep":{"direction":"0"}}} |
| 25 | +# PTZ vertical by step {"method":"do","motor":{"movestep":{"direction":"90"}}} |
| 26 | +# stop PTZ {"method":"do","motor":{"stop":"null"}} |
| 27 | +# add PTZ preset position {"method":"do","preset":{"set_preset":{"name":"name","save_ptz":"1"}}} |
| 28 | +# lens mask {"method":"set","lens_mask":{"lens_mask_info":{"enabled":"on"}}} |
| 29 | +# |
| 30 | +# https://github.com/likaci/mercury-ipc-control |
| 31 | + |
| 32 | +# ref https://github.com/gyje/tplink_encrypt/blob/9d93c2853169038e25f4e99ba6c4c7b833d5957f/tpencrypt.py |
| 33 | +def tp_encrypt(password): |
| 34 | + a = 'RDpbLfCPsJZ7fiv' |
| 35 | + c = 'yLwVl0zKqws7LgKPRQ84Mdt708T1qQ3Ha7xv3H7NyU84p21BriUWBU43odz3iP4rBL3cD02KZciXTysVXiV8ngg6vL48rPJyAUw0HurW20xqxv9aYb4M9wK1Ae0wlro510qXeU07kV57fQMc8L6aLgMLwygtc0F10a0Dg70TOoouyFhdysuRMO51yY5ZlOZZLEal1h0t9YQW0Ko7oBwmCAHoic4HYbUyVeU3sfQ1xtXcPcf1aT303wAQhv66qzW ' |
| 36 | + b = password |
| 37 | + e = '' |
| 38 | + f, g, h, k, l = 187, 187, 187, 187, 187 |
| 39 | + n = 187 |
| 40 | + g = len(a) |
| 41 | + h = len(b) |
| 42 | + k = len(c) |
| 43 | + if g > h: |
| 44 | + f = g |
| 45 | + else: |
| 46 | + f = h |
| 47 | + for p in list(range(0, f)): |
| 48 | + n = l = 187 |
| 49 | + if p >= g: |
| 50 | + n = ord(b[p]) |
| 51 | + else: |
| 52 | + if p >= h: |
| 53 | + l = ord(a[p]) |
| 54 | + else: |
| 55 | + l = ord(a[p]) |
| 56 | + n = ord(b[p]) |
| 57 | + e += c[(l ^ n) % k] |
| 58 | + return e |
| 59 | + |
| 60 | + |
| 61 | +# ref https://www.cnblogs.com/masako/p/7660418.html |
| 62 | +def convert_rsa_key(s): |
| 63 | + b_str = base64.b64decode(s) |
| 64 | + if len(b_str) < 162: |
| 65 | + return False |
| 66 | + hex_str = b_str.hex() |
| 67 | + m_start = 29 * 2 |
| 68 | + e_start = 159 * 2 |
| 69 | + m_len = 128 * 2 |
| 70 | + e_len = 3 * 2 |
| 71 | + modulus = hex_str[m_start:m_start + m_len] |
| 72 | + exponent = hex_str[e_start:e_start + e_len] |
| 73 | + return modulus, exponent |
| 74 | + |
| 75 | + |
| 76 | +def rsa_encrypt(string, pubkey): |
| 77 | + key = convert_rsa_key(pubkey) |
| 78 | + modulus = int(key[0], 16) |
| 79 | + exponent = int(key[1], 16) |
| 80 | + rsa_pubkey = rsa.PublicKey(modulus, exponent) |
| 81 | + crypto = rsa.encrypt(string.encode(), rsa_pubkey) |
| 82 | + return base64.b64encode(crypto) |
| 83 | + |
| 84 | + |
| 85 | +def get_stok(url, username, password): |
| 86 | + # get key nonce |
| 87 | + #print("-get rsa and nonce") |
| 88 | + #j = post_data(url, json.dumps({"method": "do", "login": {}})) |
| 89 | + #key = unquote(j['data']['key']) |
| 90 | + #nonce = str(j['data']['nonce']) |
| 91 | + #print("rsa: ", key) |
| 92 | + #print("nonce: ", nonce) |
| 93 | + |
| 94 | + # encrypt tp |
| 95 | + print("--encrypt password by tp") |
| 96 | + tp_password = tp_encrypt(password) |
| 97 | + #tp_password += ":" + nonce |
| 98 | + print("tp_password: ", tp_password) |
| 99 | + |
| 100 | + # rsa password |
| 101 | + #print("--encrypt password by rsa") |
| 102 | + #rsa_password = rsa_encrypt(tp_password, key) |
| 103 | + #print("rsa_password: ", rsa_password) |
| 104 | + |
| 105 | + # login |
| 106 | + d = { |
| 107 | + "method": "do", |
| 108 | + "login": { |
| 109 | + "username": username, |
| 110 | + "password": tp_password |
| 111 | + } |
| 112 | + } |
| 113 | + print("--login") |
| 114 | + j = post_data(url, json.dumps(d)) |
| 115 | + stok = j["stok"] |
| 116 | + return stok |
| 117 | + |
| 118 | + |
| 119 | +def post_data(base_url, data, stok=""): |
| 120 | + url = base_url + (("/stok=" + stok + "/ds") if stok else "") |
| 121 | + print("post: ", url, " data: ", data) |
| 122 | + r = requests.post(url, data) |
| 123 | + print("response: ", str(r.status_code), " ", str(r.json())) |
| 124 | + return r.json() |
| 125 | + |
| 126 | + |
| 127 | +if __name__ == '__main__': |
| 128 | + username = str(sys.argv[1]) |
| 129 | + password = str(sys.argv[2]) |
| 130 | + base_url = str(sys.argv[3]) |
| 131 | + data = str(sys.argv[4]) |
| 132 | + print("username: ", username) |
| 133 | + print("password: ", password) |
| 134 | + print("base_url: ", base_url) |
| 135 | + print("data: ", data) |
| 136 | + post_data(base_url, data, get_stok(base_url, username, password)) |
0 commit comments