3 * Copyright (c) 2020 Project CHIP Authors
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <app/server/OnboardingCodesUtil.h>
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>
30 constexpr char qrCodeBaseUrl[] = "https://dhrishi.github.io/connectedhomeip/qrcode.html";
31 constexpr char specialCharsUnreservedInRfc3986[] = "-._~";
33 using namespace ::chip::DeviceLayer;
35 void PrintOnboardingCodes(chip::RendezvousInformationFlags rendezvousFlags)
38 std::string manualPairingCode;
40 if (GetQRCode(QRCode, rendezvousFlags) == CHIP_NO_ERROR)
42 chip::Platform::ScopedMemoryBuffer<char> qrCodeBuffer;
43 const size_t qrCodeBufferMaxSize = 3 * QRCode.size() + 1;
44 qrCodeBuffer.Alloc(qrCodeBufferMaxSize);
46 ChipLogProgress(AppServer, "SetupQRCode: [%s]", QRCode.c_str());
47 if (EncodeQRCodeToUrl(QRCode.c_str(), QRCode.size(), &qrCodeBuffer[0], qrCodeBufferMaxSize) == CHIP_NO_ERROR)
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]);
55 ChipLogError(AppServer, "Getting QR code failed!");
58 if (GetManualPairingCode(manualPairingCode, rendezvousFlags) == CHIP_NO_ERROR)
60 ChipLogProgress(AppServer, "Manual pairing code: [%s]", manualPairingCode.c_str());
64 ChipLogError(AppServer, "Getting manual pairing code failed!");
68 static CHIP_ERROR GetSetupPayload(chip::SetupPayload & setupPayload, chip::RendezvousInformationFlags rendezvousFlags)
70 CHIP_ERROR err = CHIP_NO_ERROR;
71 setupPayload.version = 0;
72 setupPayload.rendezvousInformation = rendezvousFlags;
74 err = ConfigurationMgr().GetSetupPinCode(setupPayload.setUpPINCode);
75 VerifyOrExit(err == CHIP_NO_ERROR,
76 ChipLogProgress(AppServer, "ConfigurationMgr().GetSetupPinCode() failed: %s", chip::ErrorStr(err)));
78 err = ConfigurationMgr().GetSetupDiscriminator(setupPayload.discriminator);
79 VerifyOrExit(err == CHIP_NO_ERROR,
80 ChipLogProgress(AppServer, "ConfigurationMgr().GetSetupDiscriminator() failed: %s", chip::ErrorStr(err)));
82 err = ConfigurationMgr().GetVendorId(setupPayload.vendorID);
83 VerifyOrExit(err == CHIP_NO_ERROR,
84 ChipLogProgress(AppServer, "ConfigurationMgr().GetVendorId() failed: %s", chip::ErrorStr(err)));
86 err = ConfigurationMgr().GetProductId(setupPayload.productID);
87 VerifyOrExit(err == CHIP_NO_ERROR,
88 ChipLogProgress(AppServer, "ConfigurationMgr().GetProductId() failed: %s", chip::ErrorStr(err)));
94 CHIP_ERROR GetQRCode(std::string & QRCode, chip::RendezvousInformationFlags rendezvousFlags)
96 CHIP_ERROR err = CHIP_NO_ERROR;
97 chip::SetupPayload payload;
99 err = GetSetupPayload(payload, rendezvousFlags);
100 VerifyOrExit(err == CHIP_NO_ERROR, ChipLogProgress(AppServer, "GetSetupPayload() failed: %s", chip::ErrorStr(err)));
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)));
111 CHIP_ERROR GetManualPairingCode(std::string & manualPairingCode, chip::RendezvousInformationFlags rendezvousFlags)
113 CHIP_ERROR err = CHIP_NO_ERROR;
114 chip::SetupPayload payload;
116 err = GetSetupPayload(payload, rendezvousFlags);
117 VerifyOrExit(err == CHIP_NO_ERROR, ChipLogProgress(AppServer, "GetSetupPayload() failed: %s", chip::ErrorStr(err)));
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)));
127 static inline bool isCharUnreservedInRfc3986(const char c)
129 return isalpha(c) || isdigit(c) || (strchr(specialCharsUnreservedInRfc3986, c) != nullptr);
132 CHIP_ERROR EncodeQRCodeToUrl(const char * QRCode, size_t len, char * url, size_t maxSize)
134 const char upperHexDigits[] = "0123456789ABCDEF";
135 CHIP_ERROR err = CHIP_NO_ERROR;
138 VerifyOrExit((QRCode != nullptr) && (url != nullptr), err = CHIP_ERROR_INVALID_ARGUMENT);
140 for (i = 0; i < len; ++i)
142 unsigned char c = QRCode[i];
143 if (isCharUnreservedInRfc3986(c))
146 VerifyOrExit((j + 1) < maxSize, err = CHIP_ERROR_BUFFER_TOO_SMALL);
153 VerifyOrExit((j + 3) < maxSize, err = CHIP_ERROR_BUFFER_TOO_SMALL);
156 url[j++] = upperHexDigits[(c & 0xf0) >> 4];
157 url[j++] = upperHexDigits[(c & 0x0f)];