]> git.basschouten.com Git - openhab-addons.git/blob
5a5a34396fe6d533e21b73c6752585272d94fed1
[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.anel.internal.auth;
14
15 import java.util.Base64;
16 import java.util.regex.Matcher;
17 import java.util.regex.Pattern;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21
22 /**
23  * This class determines the authentication method from a status response of an ANEL device.
24  *
25  * @author Patrick Koenemann - Initial contribution
26  */
27 @NonNullByDefault
28 public class AnelAuthentication {
29
30     public enum AuthMethod {
31         PLAIN,
32         BASE64,
33         XORBASE64;
34
35         private static final Pattern NAME_AND_FIRMWARE_PATTERN = Pattern.compile(":NET-PWRCTRL_0?(\\d+\\.\\d)");
36         private static final Pattern LAST_SEGMENT_FIRMWARE_PATTERN = Pattern.compile(":(\\d+\\.\\d)$");
37
38         private static final String MIN_FIRMWARE_BASE64 = "6.0";
39         private static final String MIN_FIRMWARE_XOR_BASE64 = "6.1";
40
41         public static AuthMethod of(String status) {
42             if (status.isEmpty()) {
43                 return PLAIN; // fallback
44             }
45             if (status.trim().endsWith(":xor") || status.contains(":xor:")) {
46                 return XORBASE64;
47             }
48             final String firmwareVersion = getFirmwareVersion(status);
49             if (firmwareVersion == null) {
50                 return PLAIN;
51             }
52             if (firmwareVersion.compareTo(MIN_FIRMWARE_XOR_BASE64) >= 0) {
53                 return XORBASE64; // >= 6.1
54             }
55             if (firmwareVersion.compareTo(MIN_FIRMWARE_BASE64) >= 0) {
56                 return BASE64; // exactly 6.0
57             }
58             return PLAIN; // fallback
59         }
60
61         private static @Nullable String getFirmwareVersion(String fullStatusStringOrFirmwareVersion) {
62             final Matcher matcher1 = NAME_AND_FIRMWARE_PATTERN.matcher(fullStatusStringOrFirmwareVersion);
63             if (matcher1.find()) {
64                 return matcher1.group(1);
65             }
66             final Matcher matcher2 = LAST_SEGMENT_FIRMWARE_PATTERN.matcher(fullStatusStringOrFirmwareVersion.trim());
67             if (matcher2.find()) {
68                 return matcher2.group(1);
69             }
70             return null;
71         }
72     }
73
74     public static String getUserPasswordString(@Nullable String user, @Nullable String password,
75             @Nullable AuthMethod authMethod) {
76         final String userPassword = (user == null ? "" : user) + (password == null ? "" : password);
77         if (authMethod == null || authMethod == AuthMethod.PLAIN) {
78             return userPassword;
79         }
80
81         if (authMethod == AuthMethod.BASE64 || password == null || password.isEmpty()) {
82             return Base64.getEncoder().encodeToString(userPassword.getBytes());
83         }
84
85         if (authMethod == AuthMethod.XORBASE64) {
86             final StringBuilder result = new StringBuilder();
87
88             // XOR
89             for (int c = 0; c < userPassword.length(); c++) {
90                 result.append((char) (userPassword.charAt(c) ^ password.charAt(c % password.length())));
91             }
92
93             return Base64.getEncoder().encodeToString(result.toString().getBytes());
94         }
95
96         throw new UnsupportedOperationException("Unknown auth method: " + authMethod);
97     }
98 }