]> git.basschouten.com Git - openhab-addons.git/blob
da480fb6aebc0b7c82341395b3b53b5887c9932b
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.mynice.internal.xml;
14
15 import java.security.MessageDigest;
16 import java.security.NoSuchAlgorithmException;
17 import java.util.Base64;
18 import java.util.Base64.Encoder;
19 import java.util.UUID;
20
21 import javax.xml.bind.DatatypeConverter;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.openhab.binding.mynice.internal.xml.dto.CommandType;
25 import org.openhab.binding.mynice.internal.xml.dto.T4Command;
26
27 /**
28  * The {@link RequestBuilder} is responsible for building a string request from the CommandType
29  *
30  * @author GaĆ«l L'hopital - Initial contribution
31  */
32 @NonNullByDefault
33 public class RequestBuilder {
34     private static final Encoder BASE64_ENCODER = Base64.getEncoder();
35
36     public static final String USERNAME = "%un%";
37     public static final String CLIENT_CHALLENGE = "%cc%";
38     private static final String START_REQUEST = "<Request id=\"%s\" source=\"openhab\" target=\"%s\" gw=\"gwID\" protocolType=\"NHK\" protocolVersion=\"1.0\" type=\"%s\">\r\n";
39     private static final String END_REQUEST = "%s%s</Request>";
40     private static final String DOOR_ACTION = "<DoorAction>%s</DoorAction>";
41     private static final String T4_ACTION = "<T4Action>%s</T4Action>";
42     private static final String SIGN = "<Sign>%s</Sign>";
43
44     private final String clientChallenge = UUID.randomUUID().toString().substring(0, 8);
45     private final byte[] clientChallengeArr = invertArray(DatatypeConverter.parseHexBinary(clientChallenge));
46     private final MessageDigest digest;
47     private final String it4WifiMac;
48     private final String username;
49
50     private int sessionId = 0;
51     private int commandSequence = 0;
52     private byte[] sessionPassword = {};
53
54     public RequestBuilder(String it4WifiMac, String username) {
55         try {
56             this.digest = MessageDigest.getInstance("SHA-256");
57             this.it4WifiMac = it4WifiMac;
58             this.username = username;
59         } catch (NoSuchAlgorithmException e) {
60             throw new IllegalArgumentException(e);
61         }
62     }
63
64     private String buildSign(CommandType command, String message) {
65         if (command.signNeeded) {
66             byte[] msgHash = sha256(message.getBytes());
67             byte[] sign = sha256(msgHash, sessionPassword);
68             return String.format(SIGN, BASE64_ENCODER.encodeToString(sign));
69         }
70         return "";
71     }
72
73     public String buildMessage(String id, String command) {
74         return buildMessage(CommandType.CHANGE, id, String.format(DOOR_ACTION, command.toLowerCase()));
75     }
76
77     public String buildMessage(String id, T4Command t4) {
78         return buildMessage(CommandType.CHANGE, id, String.format(T4_ACTION, t4.name()));
79     }
80
81     public String buildMessage(CommandType command, Object... bodyParms) {
82         String startRequest = String.format(START_REQUEST, getCommandId(), it4WifiMac, command);
83         String body = startRequest + getBody(command, bodyParms);
84         String sign = buildSign(command, body);
85         return String.format(END_REQUEST, body, sign);
86     }
87
88     public String getBody(CommandType command, Object... bodyParms) {
89         String result = command.body;
90         if (result.length() != 0) {
91             result = result.replace(USERNAME, username);
92             result = result.replace(CLIENT_CHALLENGE, clientChallenge);
93             result = String.format(result, bodyParms);
94         }
95         return result;
96     }
97
98     public int getCommandId() {
99         return (commandSequence++ << 8) | sessionId;
100     }
101
102     public void setChallenges(String serverChallenge, int sessionId, String password) {
103         byte[] serverChallengeArr = invertArray(DatatypeConverter.parseHexBinary(serverChallenge));
104         byte[] pairingPassword = Base64.getDecoder().decode(password);
105         this.sessionPassword = sha256(pairingPassword, serverChallengeArr, clientChallengeArr);
106         this.sessionId = sessionId & 255;
107     }
108
109     private byte[] sha256(byte[]... values) {
110         for (byte[] data : values) {
111             digest.update(data);
112         }
113         return digest.digest();
114     }
115
116     private static byte[] invertArray(byte[] data) {
117         byte[] result = new byte[data.length];
118         int i = data.length - 1;
119         int c = 0;
120         while (i >= 0) {
121             int c2 = c + 1;
122             result[c] = data[i];
123             i--;
124             c = c2;
125         }
126         return result;
127     }
128 }