Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / app / server / OnboardingCodesUtil.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    All rights reserved.
5  *
6  *    Licensed under the Apache License, Version 2.0 (the "License");
7  *    you may not use this file except in compliance with the License.
8  *    You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *    Unless required by applicable law or agreed to in writing, software
13  *    distributed under the License is distributed on an "AS IS" BASIS,
14  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *    See the License for the specific language governing permissions and
16  *    limitations under the License.
17  */
18
19 #include <app/server/OnboardingCodesUtil.h>
20
21 #include <inttypes.h>
22
23 #include <platform/CHIPDeviceLayer.h>
24 #include <setup_payload/ManualSetupPayloadGenerator.h>
25 #include <setup_payload/QRCodeSetupPayloadGenerator.h>
26 #include <support/CodeUtils.h>
27 #include <support/ScopedBuffer.h>
28 #include <support/logging/CHIPLogging.h>
29
30 constexpr char qrCodeBaseUrl[]                   = "https://dhrishi.github.io/connectedhomeip/qrcode.html";
31 constexpr char specialCharsUnreservedInRfc3986[] = "-._~";
32
33 using namespace ::chip::DeviceLayer;
34
35 void PrintOnboardingCodes(chip::RendezvousInformationFlags rendezvousFlags)
36 {
37     std::string QRCode;
38     std::string manualPairingCode;
39
40     if (GetQRCode(QRCode, rendezvousFlags) == CHIP_NO_ERROR)
41     {
42         chip::Platform::ScopedMemoryBuffer<char> qrCodeBuffer;
43         const size_t qrCodeBufferMaxSize = 3 * QRCode.size() + 1;
44         qrCodeBuffer.Alloc(qrCodeBufferMaxSize);
45
46         ChipLogProgress(AppServer, "SetupQRCode: [%s]", QRCode.c_str());
47         if (EncodeQRCodeToUrl(QRCode.c_str(), QRCode.size(), &qrCodeBuffer[0], qrCodeBufferMaxSize) == CHIP_NO_ERROR)
48         {
49             ChipLogProgress(AppServer, "Copy/paste the below URL in a browser to see the QR Code:");
50             ChipLogProgress(AppServer, "%s?data=%s", qrCodeBaseUrl, &qrCodeBuffer[0]);
51         }
52     }
53     else
54     {
55         ChipLogError(AppServer, "Getting QR code failed!");
56     }
57
58     if (GetManualPairingCode(manualPairingCode, rendezvousFlags) == CHIP_NO_ERROR)
59     {
60         ChipLogProgress(AppServer, "Manual pairing code: [%s]", manualPairingCode.c_str());
61     }
62     else
63     {
64         ChipLogError(AppServer, "Getting manual pairing code failed!");
65     }
66 }
67
68 static CHIP_ERROR GetSetupPayload(chip::SetupPayload & setupPayload, chip::RendezvousInformationFlags rendezvousFlags)
69 {
70     CHIP_ERROR err                     = CHIP_NO_ERROR;
71     setupPayload.version               = 0;
72     setupPayload.rendezvousInformation = rendezvousFlags;
73
74     err = ConfigurationMgr().GetSetupPinCode(setupPayload.setUpPINCode);
75     VerifyOrExit(err == CHIP_NO_ERROR,
76                  ChipLogProgress(AppServer, "ConfigurationMgr().GetSetupPinCode() failed: %s", chip::ErrorStr(err)));
77
78     err = ConfigurationMgr().GetSetupDiscriminator(setupPayload.discriminator);
79     VerifyOrExit(err == CHIP_NO_ERROR,
80                  ChipLogProgress(AppServer, "ConfigurationMgr().GetSetupDiscriminator() failed: %s", chip::ErrorStr(err)));
81
82     err = ConfigurationMgr().GetVendorId(setupPayload.vendorID);
83     VerifyOrExit(err == CHIP_NO_ERROR,
84                  ChipLogProgress(AppServer, "ConfigurationMgr().GetVendorId() failed: %s", chip::ErrorStr(err)));
85
86     err = ConfigurationMgr().GetProductId(setupPayload.productID);
87     VerifyOrExit(err == CHIP_NO_ERROR,
88                  ChipLogProgress(AppServer, "ConfigurationMgr().GetProductId() failed: %s", chip::ErrorStr(err)));
89
90 exit:
91     return err;
92 }
93
94 CHIP_ERROR GetQRCode(std::string & QRCode, chip::RendezvousInformationFlags rendezvousFlags)
95 {
96     CHIP_ERROR err = CHIP_NO_ERROR;
97     chip::SetupPayload payload;
98
99     err = GetSetupPayload(payload, rendezvousFlags);
100     VerifyOrExit(err == CHIP_NO_ERROR, ChipLogProgress(AppServer, "GetSetupPayload() failed: %s", chip::ErrorStr(err)));
101
102     // TODO: Usage of STL will significantly increase the image size, this should be changed to more efficient method for
103     // generating payload
104     err = chip::QRCodeSetupPayloadGenerator(payload).payloadBase41Representation(QRCode);
105     VerifyOrExit(err == CHIP_NO_ERROR, ChipLogProgress(AppServer, "Generating QR Code failed: %s", chip::ErrorStr(err)));
106
107 exit:
108     return err;
109 }
110
111 CHIP_ERROR GetManualPairingCode(std::string & manualPairingCode, chip::RendezvousInformationFlags rendezvousFlags)
112 {
113     CHIP_ERROR err = CHIP_NO_ERROR;
114     chip::SetupPayload payload;
115
116     err = GetSetupPayload(payload, rendezvousFlags);
117     VerifyOrExit(err == CHIP_NO_ERROR, ChipLogProgress(AppServer, "GetSetupPayload() failed: %s", chip::ErrorStr(err)));
118
119     err = chip::ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(manualPairingCode);
120     VerifyOrExit(err == CHIP_NO_ERROR,
121                  ChipLogProgress(AppServer, "Generating Manual Pairing Code failed: %s", chip::ErrorStr(err)));
122
123 exit:
124     return err;
125 }
126
127 static inline bool isCharUnreservedInRfc3986(const char c)
128 {
129     return isalpha(c) || isdigit(c) || (strchr(specialCharsUnreservedInRfc3986, c) != nullptr);
130 }
131
132 CHIP_ERROR EncodeQRCodeToUrl(const char * QRCode, size_t len, char * url, size_t maxSize)
133 {
134     const char upperHexDigits[] = "0123456789ABCDEF";
135     CHIP_ERROR err              = CHIP_NO_ERROR;
136     size_t i = 0, j = 0;
137
138     VerifyOrExit((QRCode != nullptr) && (url != nullptr), err = CHIP_ERROR_INVALID_ARGUMENT);
139
140     for (i = 0; i < len; ++i)
141     {
142         unsigned char c = QRCode[i];
143         if (isCharUnreservedInRfc3986(c))
144         {
145
146             VerifyOrExit((j + 1) < maxSize, err = CHIP_ERROR_BUFFER_TOO_SMALL);
147
148             url[j++] = c;
149         }
150         else
151         {
152
153             VerifyOrExit((j + 3) < maxSize, err = CHIP_ERROR_BUFFER_TOO_SMALL);
154
155             url[j++] = '%';
156             url[j++] = upperHexDigits[(c & 0xf0) >> 4];
157             url[j++] = upperHexDigits[(c & 0x0f)];
158         }
159     }
160
161     url[j] = '\0';
162
163 exit:
164     return err;
165 }