~aleteoryx/muditaos

b821747851d29990a416a6b31e0ebeef3016659e — rrandomsky 2 years ago 3cc3f50
[MOS-1059] Erase only sensitive data from logs

Erase only sensitive data from logs.
M module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.cpp => module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.cpp +8 -4
@@ 16,6 16,7 @@

#include <BluetoothWorker.hpp>
#include "SCO/ScoUtils.hpp"
#include <Anonymize.hpp>

#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))



@@ 145,7 146,7 @@ namespace bluetooth
    std::uint8_t HFP::HFPImpl::serviceBuffer[serviceBufferSize];

    std::unique_ptr<SCO> HFP::HFPImpl::sco;
    SCOCodec HFP::HFPImpl::codec                       = SCOCodec::CVSD;
    SCOCodec HFP::HFPImpl::codec = SCOCodec::CVSD;
    std::shared_ptr<CVSDAudioDevice> HFP::HFPImpl::audioDevice;

    std::unique_ptr<CellularInterface> HFP::HFPImpl::cellularInterface;


@@ 202,8 203,8 @@ namespace bluetooth

    void HFP::HFPImpl::sendAudioEvent(audio::EventType event, audio::Event::DeviceState state)
    {
        auto evt       = std::make_shared<audio::Event>(event, state);
        auto msg       = std::make_shared<AudioEventRequest>(std::move(evt));
        auto evt = std::make_shared<audio::Event>(event, state);
        auto msg = std::make_shared<AudioEventRequest>(std::move(evt));
        ownerService->bus.sendUnicast(std::move(msg), service::name::evt_manager);
    }



@@ 526,7 527,10 @@ namespace bluetooth

    auto HFP::HFPImpl::setIncomingCallNumber(const std::string &num) const noexcept -> Result::Code
    {
        LOG_SENSITIVE(LOGDEBUG, "Setting number: %s", num.c_str());
        LOG_SENSITIVE(
            LOGDEBUG,
            "Setting number: %s",
            utils::anonymize::anonymizeNumbers(num, utils::anonymize::SIGNS_TO_LEAVE_FOR_PHONE_NUMBERS).c_str());
        hfp_ag_set_clip(129, num.c_str());
        return Result::Code::Success;
    }

M module-cellular/modem/ATCommon.cpp => module-cellular/modem/ATCommon.cpp +11 -6
@@ 11,6 11,7 @@
#include "ATStream.hpp"
#include <at/ATFactory.hpp>
#include <gsl/util>
#include <Anonymize.hpp>

using namespace at;
using namespace std::chrono_literals;


@@ 41,16 42,20 @@ void Channel::cmdLog(std::string cmd, const Result &result, std::chrono::millise
    } break;
    case Result::Code::ERROR: {
        LOG_ERROR("AT response: error");
        LOG_SENSITIVE(
            LOGERROR, "[AT]: >%s<, >%s<", cmd.c_str(), result.response.size() ? result.response.back().c_str() : "");
        LOG_SENSITIVE(LOGERROR,
                      "[AT]: >%s<, >%s<",
                      utils::anonymize::anonymizeCellularIfNecessary(cmd).c_str(),
                      result.response.size() ? result.response.back().c_str() : "");
    } break;
    default:
        LOG_SENSITIVE(
            LOGDEBUG, "[AT]: >%s<, >%s<", cmd.c_str(), result.response.size() ? result.response.back().c_str() : "");
        LOG_SENSITIVE(LOGDEBUG,
                      "[AT]: >%s<, >%s<",
                      utils::anonymize::anonymizeCellularIfNecessary(cmd).c_str(),
                      result.response.size() ? result.response.back().c_str() : "");
        break;
    }
    for ([[maybe_unused]] const auto &s : result.response) {
        LOG_SENSITIVE(LOGINFO, "[AT] > %s", s.c_str());
        LOG_SENSITIVE(LOGINFO, "[AT] > %s", utils::anonymize::anonymizeCellularIfNecessary(s).c_str());
    }
}



@@ 86,7 91,7 @@ Result Channel::cmd(const std::string &cmd, std::chrono::milliseconds timeout, s

    cmdInit();
    std::string cmdFixed = formatCommand(cmd);
    LOG_DEBUG("Start of %s", cmdFixed.c_str());
    LOG_DEBUG("Start of %s", utils::anonymize::anonymizeCellularIfNecessary(cmdFixed).c_str());
    cmdSend(cmdFixed);

    auto startTime = std::chrono::steady_clock::now();

M module-cellular/modem/ATCommon.hpp => module-cellular/modem/ATCommon.hpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +2 -1
@@ 98,6 98,7 @@
#include <ticks.hpp>

#include "ServiceCellularPriv.hpp"
#include "Anonymize.hpp"
#include <service-cellular/api/request/sim.hpp>
#include <service-cellular/api/notification/notification.hpp>



@@ 973,7 974,7 @@ std::optional<std::shared_ptr<sys::Message>> ServiceCellular::identifyNotificati
    const std::string str(data.begin(), data.end());

    const std::string logStr = utils::removeNewLines(str);
    LOG_SENSITIVE(LOGDEBUG, "Notification:: %s", logStr.c_str());
    LOG_SENSITIVE(LOGDEBUG, "Notification:: %s", utils::anonymize::anonymizeCellularIfNecessary(logStr).c_str());

    auto urc = at::urc::UrcFactory::Create(str);
    urc->Handle(urcHandler);

A module-utils/utility/Anonymize.cpp => module-utils/utility/Anonymize.cpp +141 -0
@@ 0,0 1,141 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "Anonymize.hpp"

namespace utils::anonymize
{
    // Anonymized text will replace by this character
    constexpr auto anonymizationCharacter = '*';

    // Amount of 'anonymizationCharacter' used during anonymization can be fixed,
    // otherwise their amount depend on length of substring to anonymize
    constexpr auto isAmountOfAnonymizationCharactersFixed = false;
    constexpr auto fixedAmountOfAnonymizationCharacters   = 4;

    // Substrings to find logs for anonymization from the cellular logs
    constexpr auto cellularSubstringCPIN = "CPIN";
    constexpr auto cellularSubstringCLCC = "CLCC";
    constexpr auto cellularSubstringATD  = "ATD";
    constexpr auto cellularSubstringCPBR = "CPBR";
    constexpr auto cellularSubstringCSPN = "CSPN";

    std::string anonymizeInQuotationMarks(const std::string &textToAnonymize, std::size_t singsToLeaveAtEnd)
    {
        constexpr auto quotesMark = '\"';
        std::size_t startPosition = 0;
        std::size_t endPosition   = 0;
        auto anonymizedText       = textToAnonymize;

        // Find the position of the substring within the input string
        while (startPosition < anonymizedText.length()) {
            startPosition = anonymizedText.find(quotesMark, startPosition);
            endPosition   = anonymizedText.find(quotesMark, startPosition + 1);

            if (startPosition != std::string::npos && endPosition != std::string::npos) {
                // Extract the substring between the quotes
                const auto &extractedSubstring =
                    anonymizedText.substr(startPosition + 1, endPosition - startPosition - 1);

                // Determine the length of the extracted substring
                const auto extractedLength = extractedSubstring.length();

                // Amount of signs to left can't be higher than extracted substring
                singsToLeaveAtEnd = std::min(extractedLength, singsToLeaveAtEnd);

                // Determine amount of anonymization characters
                const auto amountOfAnonymizationCharacters = isAmountOfAnonymizationCharactersFixed
                                                                 ? fixedAmountOfAnonymizationCharacters
                                                                 : extractedLength - singsToLeaveAtEnd;

                // Replace the substring with the appropriate number of '*' characters
                anonymizedText.replace(startPosition + 1,
                                       extractedLength - singsToLeaveAtEnd,
                                       amountOfAnonymizationCharacters,
                                       anonymizationCharacter);
                startPosition = endPosition + 1;
            }
            else {
                break;
            }
        }
        return anonymizedText;
    }

    std::string anonymizeNumbers(const std::string &textToAnonymize, std::size_t singsToLeaveAtEnd)
    {
        std::size_t startPosition = 0;
        std::size_t endPosition   = 0;
        auto isDigitFunction      = [](char c) { return std::isdigit(c); };
        auto anonymizedText       = textToAnonymize;
        auto startSubstring       = anonymizedText.begin();
        auto endSubstring         = anonymizedText.begin();

        while (startPosition < anonymizedText.length()) {
            // Find first number in string
            startSubstring = std::find_if(endSubstring, anonymizedText.end(), isDigitFunction);

            // If first number found then find last number and anonymize whole number in string
            if (startSubstring != anonymizedText.end()) {
                endSubstring = std::find_if_not(startSubstring, anonymizedText.end(), isDigitFunction);

                // Calculate positions
                startPosition = std::distance(anonymizedText.begin(), startSubstring);
                endPosition   = std::distance(anonymizedText.begin(), endSubstring);

                if (startPosition != std::string::npos && endPosition != std::string::npos) {
                    // Extract the substring contained only numbers
                    const auto &extractedSubstring =
                        anonymizedText.substr(startPosition + 1, endPosition - startPosition);

                    // Determine the length of the extracted substring
                    const auto extractedLength = extractedSubstring.length();

                    // Amount of signs to left can't be higher than extracted substring
                    singsToLeaveAtEnd = std::min(extractedLength, singsToLeaveAtEnd);

                    // Determine amount of anonymization characters
                    const auto amountOfAnonymizationCharacters = isAmountOfAnonymizationCharactersFixed
                                                                     ? fixedAmountOfAnonymizationCharacters
                                                                     : extractedLength - singsToLeaveAtEnd;

                    // Replace the substring with the appropriate number of '*' characters
                    anonymizedText.replace(startPosition,
                                           extractedLength - singsToLeaveAtEnd,
                                           amountOfAnonymizationCharacters,
                                           anonymizationCharacter);

                    startPosition = endPosition + 1;
                }
                else {
                    break;
                }
            }
            else {
                break;
            }
        }
        return anonymizedText;
    }

    std::string anonymizeCellularIfNecessary(const std::string &text)
    {
        std::map<std::string, std::function<std::string()>> anonymizeOption{
            {cellularSubstringCPIN,
             [&text]() { return anonymizeInQuotationMarks(text, SIGNS_TO_LEAVE_FOR_PIN_AND_PUK); }},
            {cellularSubstringCLCC,
             [&text]() { return anonymizeInQuotationMarks(text, SIGNS_TO_LEAVE_FOR_PHONE_NUMBERS); }},
            {cellularSubstringATD, [&text]() { return anonymizeNumbers(text, SIGNS_TO_LEAVE_FOR_PHONE_NUMBERS); }},
            {cellularSubstringCPBR,
             [&text]() { return anonymizeInQuotationMarks(text, SIGNS_TO_LEAVE_FOR_PHONE_NUMBERS); }},
            {cellularSubstringCSPN,
             [&text]() { return anonymizeInQuotationMarks(text, SIGNS_TO_LEAVE_FOR_NET_PROVIDER_NAME); }}};

        for (const auto &[key, anonymizeFunction] : anonymizeOption) {
            if (text.find(key) != std::string::npos) {
                return anonymizeFunction();
            }
        }
        return text;
    }
} // namespace utils::anonymize

A module-utils/utility/Anonymize.hpp => module-utils/utility/Anonymize.hpp +25 -0
@@ 0,0 1,25 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <string>
#include <algorithm>
#include <functional>
#include <map>

namespace utils::anonymize
{
    // Determine how many characters to leave at the end of anonymized substring
    constexpr auto SIGNS_TO_LEAVE_FOR_PIN_AND_PUK       = 0;
    constexpr auto SIGNS_TO_LEAVE_FOR_PHONE_NUMBERS     = 2;
    constexpr auto SIGNS_TO_LEAVE_FOR_NET_PROVIDER_NAME = 1;

    // Basic function to anonymize provided string
    std::string anonymizeInQuotationMarks(const std::string &textToAnonymize, std::size_t singsToLeaveAtEnd = 0);
    std::string anonymizeNumbers(const std::string &textToAnonymize, std::size_t singsToLeaveAtEnd = 0);

    // To anonymize logs from cellular
    std::string anonymizeCellularIfNecessary(const std::string &text);

} // namespace utils::anonymize

M module-utils/utility/CMakeLists.txt => module-utils/utility/CMakeLists.txt +2 -0
@@ 3,6 3,7 @@ add_library(utility STATIC)
target_sources(utility
    PRIVATE
        Utils.cpp
        Anonymize.cpp

    PUBLIC
        integer.hpp


@@ 12,6 13,7 @@ target_sources(utility
        Utility.hpp
        Utils.hpp
        Units.hpp
        Anonymize.hpp
)

target_include_directories(utility

M pure_changelog.md => pure_changelog.md +1 -0
@@ 9,6 9,7 @@
### Changed / Improved

* Hide the SOS label during onboarding when the modem is not ready for an emergency call.
* Anonymization sensitive data in logs added.

### Fixed