-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deco S7 - Fetch keys 401 unauthorized #130
Comments
Follow steps in Additional Debugging https://github.com/amosyuen/ha-tplink-deco/blob/master/DEBUGGING.md and find what the request for fetch keys looks like |
Ok, I did the advanced debugging part, I did find some Quick note - the command in the documentation did not work: However this was successful: The output was: |
Hmm, since you didn't see an http call that looks like You should only get logged out if the authentication suceeds, so it's expected that you didn't get logged out since it failed. It is rather difficult to reverse engineer the API remotely, so we'll probably have to wait for a programmer who has a deco with incompatible firmware to look into it. For now I'll add your model and firmware to the README as incompatible. |
Same error with a Deco X60 mesh… |
Still happens with 1.3.3 firmware? |
Yes, still happens with 1.3.3 firmware. This is not an issue on the Deco side, they just seem to use different requests with the newer Deco models. I am a developer myself, but not with Python but with .NET. I am still pretty new to creating/modifying integrations, so if someone that has more experience is willing to help, I can look into this. |
@Nedevski I can help with the HA integration part, the difficult part is reverse engineering TP-Link's calls and encryption scheme. In the old decos they do some encryption with RSA and AES, generating payloads with matching signs. Honestly I only figured it out from looking at other libraries / blog posts. Hopefully they haven't changed the encryption scheme too much. |
Anyone working on a solution for the Deco S7? |
I just had a small breaktrough. So it looks like after you are logged in, you poll 3 different endpoints - network, device, client. All requests are in the form of
Without any additional parameters I was able to get a full readable JSON with all my devices:
I will look into it a bit more later today and will report if I find anything. If someone is a bit more familiar with encryption in general and is willing to waste a bit of time on this - ping me. |
As far as I understand the new authentication method has 4 "steps" to login. Step 1:
Step 2:
Step 3:
Step 3:
Every step returns
That If I manage to get anything else I'll share it here, hope this helps. |
Update
It sets the AES Key (i supose to decrypt on the server side?), so basically it sends the The string it encrypt is
|
Update 2
Turns out it's not random, it's an encrypted form of the password: var n = s.su.encrypt(e[3], s.encrypt.MD5(r), e[4])
return localStorage.setItem("id", n) I don't know which encryption it uses. |
doLogin functionI'm going to share the !function(s) {
s.su.moduleManager.define("localLogin", {
services: ["ajax"],
models: ["localLogin", "localLoginControl"],
stores: [],
views: ["localLoginView"],
deps: ["login", "main"],
listeners: {
"ev_on_launch": function(e, n, t, o, r, l, a) {
s.encrypt.encryptManager.cleanStorage(),
s.su.encryptor = s.encrypt.encryptManager.genEncryptor(),
localStorage.removeItem("id"),
l.main.keyDictionary = "",
l.main.getTmpKey()
}
},
init: function(n, e, t, o, r, l) {
this.control({
"#local-login-pwd": {
"keyup": function(e) {
13 == e.keyCode && n.doLogin()
}
},
"#local-login-button": {
"ev_button_click": function() {
n.doLogin()
}
},
".local-login-switch-to-tp": {
"click": function(e) {
r.login.goToChildModule("tpLogin")
}
},
".local-login-forget-pwd": {
"click": function() {
e.localLoginView.forgetPasswordMsg.show()
}
}
})
}
}, function(l, c, i, e, a, n) {
return {
encryptKey: null,
doLogin: function() {
if (i.localLoginControl.password.validate()) {
var r = i.localLoginControl.password.getValue();
c.localLoginView.loginBtn.disable(),
a.main.getTmpKey().then(function(e) {
return l.enableGDPR(e)
}).then(function(e) {
var n = s.Deferred();
return l.getGDPRKey().then(function() {
n.resolve(e)
}, function() {}),
n
}).then(function(e) {
var n = s.su.encrypt(e[3], s.encrypt.MD5(r), e[4])
, o = s.Deferred()
, t = s.encrypt.encryptManager.getEncryptor();
return localStorage.setItem("id", n),
s.ajax({
url: s.su.url("?code=7&asyn=0"),
data: t.rsaEncrypt(r)
}).then(function(e) {
"00000" === e.split("\r\n")[0] ? (i.localLoginControl.password.setValue(null),
o.resolve()) : o.reject()
}, function(e) {
var n = e.responseText.split("\r\n");
switch (parseInt(n[1])) {
case 0:
i.localLoginControl.password.setError(s.su.CHAR.LOGIN.loginFull);
break;
case 1:
i.localLoginControl.password.disable(),
c.localLoginView.leftAttemptsMsgContent.setText(s.su.CHAR.LOGIN.loginLock),
c.localLoginView.leftAttemptsMsg.show();
break;
case 2:
i.localLoginControl.password.setError(s.su.CHAR.LOGIN.loginTimeout);
break;
case 3:
case 5:
var t = n[2] == undefined ? 10 : 10 - parseInt(n[2]);
if (10 === t)
break;
l.disableButton(c.localLoginView.loginBtn),
t <= 5 ? (c.localLoginView.leftAttemptsMsgContent.setText(s.su.CHAR.LOGIN.loginErrorTipH.replace("%s", t)),
c.localLoginView.leftAttemptsMsg.show()) : i.localLoginControl.password.setError(s.su.CHAR.LOGIN.loginPwdErr);
break;
case 6:
l.disableButton(c.localLoginView.loginBtn),
i.localLoginControl.password.setError(s.su.CHAR.LOGIN.loginPwdErr)
}
o.reject()
}),
o
}).then(function() {
return l.setGDPRKey()
}).then(function() {
a.main.loadBasicModule("index")
}).always(function() {
0 < l.countDownSec || c.localLoginView.loginBtn.enable()
})
}
},
loginSuccessDealer: function(e, n) {
var t, o, r, l = e.stok || (t = "12345",
o = top.location.href,
0 <= (r = o.indexOf("stok=")) && (t = o.substring(r + 5)),
t);
localStorage && (a.main.setToken(l),
a.main.reload())
},
loginFailDealer: function(e, n) {
var t = e.result;
switch (c.localLoginView.loginBtn.enable(),
n) {
case -5002:
var o, r = t.failureCount, l = t.attemptsAllowed;
if (r < 7) {
var a = String(-5002).replace(/^-/, "E");
i.localLoginControl.password.setError(s.su.CHAR.ERROR[a])
} else
o = s.su.CHAR.LOGIN.LOGIN_FAILED_COUNT.replace("%num1", r).replace("%num2", l),
c.localLoginView.leftAttemptsMsgContent.setText(o),
c.localLoginView.leftAttemptsMsg.show();
break;
case -5003:
c.localLoginView.maxAttemptsMsgContent.setText(s.su.CHAR.ERROR["00000089"]),
c.localLoginView.maxAttemptsMsg.show()
}
},
queryRecoveryPasswordMethod: function() {
var e = s.Deferred();
return e.resolve(!0),
e.promise()
},
enableGDPR: function(n) {
var t = s.Deferred();
return s.ajax({
url: s.su.url("?code=16&asyn=0"),
data: "enable"
}).then(function(e) {
"00000" === e.split("\r\n")[0] ? t.resolve(n) : t.reject()
}, function() {
t.reject()
}),
t
},
getGDPRKey: function() {
var n = s.Deferred()
, t = s.encrypt.encryptManager.getEncryptor() || s.encrypt.encryptManager.genEncryptor();
return s.ajax({
url: s.su.url("/?code=16&asyn=0"),
data: "get"
}).then(function(e) {
data = e.split("\r\n"),
"00000" === data[0] ? (t.setRSAKey(data[2], data[1]),
t.setSeq(data[3]),
t.genAESKey(),
s.encrypt.encryptManager.recordEncryptor(),
n.resolve()) : n.reject()
}, function() {
n.reject()
}),
n
},
setGDPRKey: function() {
var n = s.Deferred()
, e = s.encrypt.encryptManager.getEncryptor();
return s.ajax({
url: s.su.url("/?code=16&asyn=0"),
data: "set " + e.getEncodeAESKey()
}).then(function(e) {
"00000" === e.split("\r\n")[0] ? n.resolve() : n.reject()
}, function() {
n.reject()
}),
n
},
disableButton: function(e) {
l.countDownSec = 30,
e.setText(s.su.CHAR.LOGIN.LOGIN_BUTTON_COUNTDOWN.replace("%num%", l.countDownSec)),
l.intervalId = setInterval(function n() {
l.countDownSec--,
0 < l.countDownSec ? e.setText(s.su.CHAR.LOGIN.LOGIN_BUTTON_COUNTDOWN.replace("%num%", l.countDownSec)) : (clearInterval(l.intervalId),
e.enable(),
e.setText(s.su.CHAR.LOGIN.LOGIN_BUTTON_TEXT))
}, 1e3),
e.disable()
}
}
})
}(jQuery); |
Version of the custom_component
v2.2.3
Deco Model
Deco S7 (1.3.0 Build 20220609 Rel. 64814)
Describe the bug
Just got 2 different Deco networks and I'm trying to add them to 2 different HA instances (one of them is fresh).
I get the same result, I am using the settings below.
The IP of the root node is correct, the password is correct.
At my main HA instance I got some 2-3 second delay the first time I tried to add it and then it was an immediate error afterwards
Checked the logs and they don't provide any meaningful info for me, just straight 401's
I saw the other issue, however my error messages are different and that's why I'm opening a new issue.
Debug log
The text was updated successfully, but these errors were encountered: