[sunsynk] Adapt to user logon requires a nonce and sign. (#19741)

* restore development environment

Signed-off-by: LeeC77 <lee.charlton00@gmail.com>
This commit is contained in:
Lee Charlton
2025-12-05 17:20:27 +01:00
committed by GitHub
parent c4a2425165
commit ae29d36f11
3 changed files with 34 additions and 17 deletions
@@ -89,8 +89,9 @@ public class AccountController {
public void clientAuthenticate(String username, String userPassword)
throws SunSynkClientAuthenticateException, SunSynkAuthenticateException {
long nonce = Instant.now().toEpochMilli();
String signSource = "nonce=" + nonce + "&source=" + SOURCE + SECRET_KEY;
try {
String authEndpoint = "nonce=" + String.valueOf(nonce) + "&source=" + SOURCE + "&sign=" + getSign(nonce);
String authEndpoint = "nonce=" + nonce + "&source=" + SOURCE + "&sign=" + getSign(signSource);
httpGetPublicKey(authEndpoint);
String encryptedPassword = getEncryptPassword(userPassword, this.publicKey.getPublicKey());
userAuthenticate(username, encryptedPassword);
@@ -123,8 +124,20 @@ public class AccountController {
* @throws SunSynkTokenException
*/
public void userAuthenticate(String username, String saltedPassword)
throws SunSynkAuthenticateException, SunSynkTokenException {
String payload = makeLoginBody(username, saltedPassword);
throws SunSynkAuthenticateException, SunSynkTokenException, SunSynkClientAuthenticateException {
long nonce = Instant.now().toEpochMilli();
String publicKeyString = this.publicKey.getPublicKey();
if (publicKeyString.length() < 10) {
throw new SunSynkClientAuthenticateException("Public key is too short");
}
String signSource = "nonce=" + nonce + "&source=" + SOURCE + publicKeyString.substring(0, 10);
String payload;
try {
payload = makeLoginBody(username, saltedPassword, getSign(signSource), nonce);
} catch (NoSuchAlgorithmException e) {
throw new SunSynkClientAuthenticateException("Error attempting to authenticate client:" + e.getMessage());
}
httpTokenPost(payload);
}
@@ -289,9 +302,9 @@ public class AccountController {
return "https://api.sunsynk.net" + "/" + path;
}
private static String makeLoginBody(String username, String password) {
private static String makeLoginBody(String username, String password, String signature, Long nonce) {
Gson gson = new Gson();
SunSynkLogin login = new SunSynkLogin(username, password);
SunSynkLogin login = new SunSynkLogin(username, password, signature, nonce);
return gson.toJson(login);
}
@@ -306,17 +319,14 @@ public class AccountController {
APIdata.staticAccessToken = data.getAccessToken();
}
private String getSign(Long nonce) throws NoSuchAlgorithmException {
String inputString = "nonce=" + String.valueOf(nonce) + "&source=" + SOURCE + SECRET_KEY;
private String getSign(String inputString) throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
byte[] hashBytes = messageDigest.digest(inputString.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : hashBytes) {
sb.append(String.format("%02x", b));
}
logger.trace("nonce : {} encrypted nonce : {}", nonce.toString(), sb.toString());
logger.trace("sign source : {} MD5 hash : {}", inputString, sb.toString());
return sb.toString();
}
@@ -26,7 +26,12 @@ import com.google.gson.annotations.SerializedName;
@NonNullByDefault
public class SunSynkLogin {
// {"username":"xxx", "password":"xxx", "grant_type":"password", "client_id":"csp-web"}
// {"sign":"MD5 sign", "nonce":"unix time", "username":"xxx", "password":"xxx", "grant_type":"password",
// "client_id":"csp-web"}
@SerializedName("sign")
private String signature = "";
@SerializedName("nonce")
private String nonce = "";
@SerializedName("username")
private String userName = "";
@SerializedName("password")
@@ -38,8 +43,10 @@ public class SunSynkLogin {
@SerializedName("source")
private String source = "sunsynk";
public SunSynkLogin(String UserName, String PassWord) {
this.userName = UserName;
this.passWord = PassWord;
public SunSynkLogin(String userName, String password, String signature, Long nonce) {
this.userName = userName;
this.passWord = password;
this.signature = signature;
this.nonce = nonce.toString();
}
}
@@ -68,10 +68,10 @@ public class SunSynkInverterHandler extends BaseThingHandler {
private @Nullable ScheduledFuture<?> refreshTask;
private boolean batterySettingsUpdated = false;
private SunSynkInverterConfig config = new SunSynkInverterConfig();
private final int INVERTERFLAGS = DeviceController.GRIDREALTIME | DeviceController.BATTERYREALTIME
private static final int INVERTERFLAGS = DeviceController.GRIDREALTIME | DeviceController.BATTERYREALTIME
| DeviceController.INVERTERDAYTEMPS | DeviceController.REALTIMEIN;
private final int SUMMARYFLAGS = DeviceController.PLANTSUMMARY;
private final int ALLFLAGS = INVERTERFLAGS | SUMMARYFLAGS;
private static final int SUMMARYFLAGS = DeviceController.PLANTSUMMARY;
private static final int ALLFLAGS = INVERTERFLAGS | SUMMARYFLAGS;
private int statusFlags = 0;
public Settings tempInverterChargeSettings = inverter.tempInverterChargeSettings; // Holds modified
// battery settings.