Matter SDK Coverage Report
Current view: top level - app/server - OnboardingCodesUtil.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 0.0 % 100 0
Test Date: 2025-01-17 19:00:11 Functions: 0.0 % 11 0

            Line data    Source code
       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 <algorithm>
      22              : #include <inttypes.h>
      23              : 
      24              : #include <lib/support/CodeUtils.h>
      25              : #include <lib/support/ScopedBuffer.h>
      26              : #include <lib/support/logging/CHIPLogging.h>
      27              : #include <platform/CHIPDeviceLayer.h>
      28              : #include <platform/CommissionableDataProvider.h>
      29              : #include <platform/DeviceInstanceInfoProvider.h>
      30              : #include <setup_payload/ManualSetupPayloadGenerator.h>
      31              : #include <setup_payload/QRCodeSetupPayloadGenerator.h>
      32              : 
      33              : constexpr char kQrCodeBaseUrl[]                   = "https://project-chip.github.io/connectedhomeip/qrcode.html";
      34              : constexpr char kUrlDataAssignmentPhrase[]         = "?data=";
      35              : constexpr char kSpecialCharsUnreservedInRfc3986[] = "-._~";
      36              : 
      37              : using namespace ::chip::DeviceLayer;
      38              : 
      39            0 : void PrintOnboardingCodes(chip::RendezvousInformationFlags aRendezvousFlags)
      40              : {
      41            0 :     chip::PayloadContents payload;
      42              : 
      43            0 :     CHIP_ERROR err = GetPayloadContents(payload, aRendezvousFlags);
      44            0 :     if (err != CHIP_NO_ERROR)
      45              :     {
      46            0 :         ChipLogError(AppServer, "GetPayloadContents() failed: %" CHIP_ERROR_FORMAT, err.Format());
      47              :     }
      48              : 
      49            0 :     PrintOnboardingCodes(payload);
      50            0 : }
      51              : 
      52            0 : void PrintOnboardingCodes(const chip::PayloadContents & payload)
      53              : {
      54              :     char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
      55            0 :     chip::MutableCharSpan qrCode(payloadBuffer);
      56              : 
      57            0 :     if (GetQRCode(qrCode, payload) == CHIP_NO_ERROR)
      58              :     {
      59            0 :         PrintQrCodeURL(qrCode);
      60              :     }
      61              :     else
      62              :     {
      63            0 :         ChipLogError(AppServer, "Getting QR code failed!");
      64              :     }
      65              : 
      66            0 :     chip::MutableCharSpan manualPairingCode(payloadBuffer);
      67            0 :     if (GetManualPairingCode(manualPairingCode, payload) == CHIP_NO_ERROR)
      68              :     {
      69            0 :         ChipLogProgress(AppServer, "Manual pairing code: [%s]", manualPairingCode.data());
      70              :     }
      71              :     else
      72              :     {
      73            0 :         ChipLogError(AppServer, "Getting manual pairing code failed!");
      74              :     }
      75            0 : }
      76              : 
      77            0 : void PrintQrCodeURL(const chip::MutableCharSpan qrCode)
      78              : {
      79            0 :     chip::Platform::ScopedMemoryBuffer<char> qrCodeBuffer;
      80            0 :     const size_t qrCodeBufferMaxSize = strlen(kQrCodeBaseUrl) + strlen(kUrlDataAssignmentPhrase) + 3 * qrCode.size() + 1;
      81            0 :     qrCodeBuffer.Alloc(qrCodeBufferMaxSize);
      82              : 
      83            0 :     ChipLogProgress(AppServer, "SetupQRCode: [%s]", qrCode.data());
      84            0 :     if (GetQRCodeUrl(qrCodeBuffer.Get(), qrCodeBufferMaxSize, qrCode) == CHIP_NO_ERROR)
      85              :     {
      86            0 :         ChipLogProgress(AppServer, "Copy/paste the below URL in a browser to see the QR Code:");
      87            0 :         ChipLogProgress(AppServer, "%s", qrCodeBuffer.Get());
      88              :     }
      89            0 : }
      90              : 
      91              : #if CHIP_DEVICE_CONFIG_ENABLE_NFC
      92              : void ShareQRCodeOverNFC(chip::RendezvousInformationFlags aRendezvousFlags)
      93              : {
      94              :     // Get QR Code and emulate its content using NFC tag
      95              :     char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
      96              :     chip::MutableCharSpan qrCode(payloadBuffer);
      97              : 
      98              :     ReturnOnFailure(GetQRCode(qrCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)));
      99              : 
     100              :     ReturnOnFailure(NFCMgr().StartTagEmulation(qrCode.data(), qrCode.size()));
     101              : }
     102              : #endif
     103              : 
     104            0 : CHIP_ERROR GetPayloadContents(chip::PayloadContents & aPayload, chip::RendezvousInformationFlags aRendezvousFlags)
     105              : {
     106            0 :     CHIP_ERROR err   = CHIP_NO_ERROR;
     107            0 :     aPayload.version = 0;
     108            0 :     aPayload.rendezvousInformation.SetValue(aRendezvousFlags);
     109              : 
     110            0 :     err = GetCommissionableDataProvider()->GetSetupPasscode(aPayload.setUpPINCode);
     111            0 :     if (err != CHIP_NO_ERROR)
     112              :     {
     113              : #if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE
     114            0 :         ChipLogProgress(AppServer, "*** Using default EXAMPLE passcode %u ***",
     115              :                         static_cast<unsigned>(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE));
     116            0 :         aPayload.setUpPINCode = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE;
     117              : #else
     118              :         ChipLogError(AppServer, "GetCommissionableDataProvider()->GetSetupPasscode() failed: %" CHIP_ERROR_FORMAT, err.Format());
     119              :         return err;
     120              : #endif
     121              :     }
     122              : 
     123            0 :     uint16_t discriminator = 0;
     124            0 :     err                    = GetCommissionableDataProvider()->GetSetupDiscriminator(discriminator);
     125            0 :     if (err != CHIP_NO_ERROR)
     126              :     {
     127            0 :         ChipLogError(AppServer, "GetCommissionableDataProvider()->GetSetupDiscriminator() failed: %" CHIP_ERROR_FORMAT,
     128              :                      err.Format());
     129            0 :         return err;
     130              :     }
     131            0 :     aPayload.discriminator.SetLongValue(discriminator);
     132              : 
     133            0 :     err = chip::DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(aPayload.vendorID);
     134            0 :     if (err != CHIP_NO_ERROR)
     135              :     {
     136            0 :         ChipLogError(AppServer, "GetDeviceInstanceInfoProvider()->GetVendorId() failed: %" CHIP_ERROR_FORMAT, err.Format());
     137            0 :         return err;
     138              :     }
     139              : 
     140            0 :     err = chip::DeviceLayer::GetDeviceInstanceInfoProvider()->GetProductId(aPayload.productID);
     141            0 :     if (err != CHIP_NO_ERROR)
     142              :     {
     143            0 :         ChipLogError(AppServer, "GetDeviceInstanceInfoProvider()->GetProductId() failed: %" CHIP_ERROR_FORMAT, err.Format());
     144            0 :         return err;
     145              :     }
     146              : 
     147            0 :     return err;
     148              : }
     149              : 
     150            0 : CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, chip::RendezvousInformationFlags aRendezvousFlags)
     151              : {
     152            0 :     chip::PayloadContents payload;
     153              : 
     154            0 :     CHIP_ERROR err = GetPayloadContents(payload, aRendezvousFlags);
     155            0 :     if (err != CHIP_NO_ERROR)
     156              :     {
     157            0 :         ChipLogError(AppServer, "GetPayloadContents() failed: %" CHIP_ERROR_FORMAT, err.Format());
     158            0 :         return err;
     159              :     }
     160              : 
     161            0 :     return GetQRCode(aQRCode, payload);
     162            0 : }
     163              : 
     164            0 : CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, const chip::PayloadContents & payload)
     165              : {
     166            0 :     CHIP_ERROR err = chip::QRCodeBasicSetupPayloadGenerator(payload).payloadBase38Representation(aQRCode);
     167            0 :     if (err != CHIP_NO_ERROR)
     168              :     {
     169            0 :         ChipLogError(AppServer, "Generating QR Code failed: %" CHIP_ERROR_FORMAT, err.Format());
     170            0 :         return err;
     171              :     }
     172              : 
     173            0 :     return CHIP_NO_ERROR;
     174              : }
     175              : 
     176            0 : CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const chip::CharSpan & aQRCode)
     177              : {
     178            0 :     VerifyOrReturnError(aQRCodeUrl, CHIP_ERROR_INVALID_ARGUMENT);
     179            0 :     VerifyOrReturnError(aUrlMaxSize >= (strlen(kQrCodeBaseUrl) + strlen(kUrlDataAssignmentPhrase) + aQRCode.size() + 1),
     180              :                         CHIP_ERROR_BUFFER_TOO_SMALL);
     181              : 
     182            0 :     const int writtenDataSize = snprintf(aQRCodeUrl, aUrlMaxSize, "%s%s", kQrCodeBaseUrl, kUrlDataAssignmentPhrase);
     183            0 :     VerifyOrReturnError((writtenDataSize > 0) && (static_cast<size_t>(writtenDataSize) < aUrlMaxSize),
     184              :                         CHIP_ERROR_INVALID_STRING_LENGTH);
     185              : 
     186            0 :     return EncodeQRCodeToUrl(aQRCode.data(), aQRCode.size(), aQRCodeUrl + writtenDataSize,
     187            0 :                              aUrlMaxSize - static_cast<size_t>(writtenDataSize));
     188              : }
     189              : 
     190            0 : CHIP_ERROR GetManualPairingCode(chip::MutableCharSpan & aManualPairingCode, chip::RendezvousInformationFlags aRendezvousFlags)
     191              : {
     192            0 :     chip::PayloadContents payload;
     193              : 
     194            0 :     CHIP_ERROR err = GetPayloadContents(payload, aRendezvousFlags);
     195            0 :     if (err != CHIP_NO_ERROR)
     196              :     {
     197            0 :         ChipLogError(AppServer, "GetPayloadContents() failed: %" CHIP_ERROR_FORMAT, err.Format());
     198            0 :         return err;
     199              :     }
     200            0 :     return GetManualPairingCode(aManualPairingCode, payload);
     201            0 : }
     202              : 
     203            0 : CHIP_ERROR GetManualPairingCode(chip::MutableCharSpan & aManualPairingCode, const chip::PayloadContents & payload)
     204              : {
     205            0 :     CHIP_ERROR err = chip::ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(aManualPairingCode);
     206            0 :     if (err != CHIP_NO_ERROR)
     207              :     {
     208            0 :         ChipLogError(AppServer, "Generating Manual Pairing Code failed: %" CHIP_ERROR_FORMAT, err.Format());
     209            0 :         return err;
     210              :     }
     211              : 
     212            0 :     return CHIP_NO_ERROR;
     213              : }
     214              : 
     215            0 : static inline bool isCharUnreservedInRfc3986(const char c)
     216              : {
     217            0 :     return isalpha(c) || isdigit(c) || (strchr(kSpecialCharsUnreservedInRfc3986, c) != nullptr);
     218              : }
     219              : 
     220            0 : CHIP_ERROR EncodeQRCodeToUrl(const char * aQRCode, size_t aLen, char * aUrl, size_t aMaxSize)
     221              : {
     222              :     static const char upperHexDigits[] = "0123456789ABCDEF";
     223            0 :     size_t i = 0, j = 0;
     224              : 
     225            0 :     VerifyOrReturnError((aQRCode != nullptr) && (aUrl != nullptr), CHIP_ERROR_INVALID_ARGUMENT);
     226              : 
     227            0 :     for (i = 0; i < aLen; ++i)
     228              :     {
     229            0 :         char c = aQRCode[i];
     230            0 :         if (isCharUnreservedInRfc3986(c))
     231              :         {
     232              : 
     233            0 :             VerifyOrReturnError((j + 1) < aMaxSize, CHIP_ERROR_BUFFER_TOO_SMALL);
     234              : 
     235            0 :             aUrl[j++] = c;
     236              :         }
     237              :         else
     238              :         {
     239              : 
     240            0 :             VerifyOrReturnError((j + 3) < aMaxSize, CHIP_ERROR_BUFFER_TOO_SMALL);
     241              : 
     242            0 :             aUrl[j++] = '%';
     243            0 :             aUrl[j++] = upperHexDigits[(c & 0xf0) >> 4];
     244            0 :             aUrl[j++] = upperHexDigits[(c & 0x0f)];
     245              :         }
     246              :     }
     247              : 
     248            0 :     aUrl[j] = '\0';
     249              : 
     250            0 :     return CHIP_NO_ERROR;
     251              : }
        

Generated by: LCOV version 2.0-1