~aleteoryx/muditaos

d5c3d41ca469c8498d66a34077a19e59ec8e56d2 — Piotr Tański 4 years ago a3d2c9f
[EGD-5204] Secure USB communication

Secure all endpoints by returning 403(Forbidden) when USB is connected.
Request screen passcode to enable secured endpoints.
59 files changed, 640 insertions(+), 82 deletions(-)

M enabled_unittests
M image/assets/lang/English.json
M image/user/db/settings_v2_002.sql
D image/user/settings.db
M module-apps/Application.cpp
M module-apps/Application.hpp
M module-apps/application-desktop/ApplicationDesktop.cpp
M module-apps/application-desktop/ApplicationDesktop.hpp
M module-apps/application-desktop/widgets/PinLockHandler.cpp
M module-apps/application-desktop/widgets/PinLockHandler.hpp
M module-apps/application-settings-new/ApplicationSettings.cpp
M module-apps/application-settings-new/ApplicationSettings.hpp
M module-apps/application-settings-new/windows/SecurityMainWindow.cpp
M module-apps/application-settings-new/windows/SecurityMainWindow.hpp
M module-bsp/board/linux/usb_cdc/usb_cdc.cpp
M module-bsp/board/rt1051/bsp/usb
M module-bsp/bsp/usb/usb.hpp
M module-services/service-appmgr/CMakeLists.txt
A module-services/service-appmgr/data/UsbActionsParams.cpp
M module-services/service-appmgr/model/ApplicationManager.cpp
M module-services/service-appmgr/service-appmgr/Actions.hpp
A module-services/service-appmgr/service-appmgr/data/UsbActionsParams.hpp
M module-services/service-db/agents/settings/SystemSettings.hpp
M module-services/service-desktop/ServiceDesktop.cpp
M module-services/service-desktop/WorkerDesktop.cpp
M module-services/service-desktop/endpoints/Endpoint.hpp
M module-services/service-desktop/endpoints/EndpointFactory.hpp
M module-services/service-desktop/endpoints/backup/BackupEndpoint.hpp
M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp
M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.hpp
M module-services/service-desktop/endpoints/restore/RestoreEndpoint.hpp
M module-services/service-desktop/parser/HttpEnums.hpp
M module-services/service-desktop/parser/MessageHandler.cpp
M module-services/service-desktop/parser/MessageHandler.hpp
M module-services/service-desktop/parser/ParserFSM.cpp
M module-services/service-desktop/parser/ParserFSM.hpp
M module-services/service-desktop/service-desktop/DesktopMessages.hpp
M module-services/service-desktop/service-desktop/ServiceDesktop.hpp
M module-services/service-desktop/service-desktop/WorkerDesktop.hpp
M module-services/service-desktop/tests/test-contacts.cpp
M module-services/service-desktop/tests/unittest.cpp
M source/MessageType.hpp
M test/harness/harness.py
M test/harness/interface/CDCSerial.py
M test/harness/interface/defs.py
M test/pytest/conftest.py
M test/pytest/service-desktop/test_backup.py
M test/pytest/service-desktop/test_battery_file.py
M test/pytest/service-desktop/test_bluetooth.py
M test/pytest/service-desktop/test_calendar.py
M test/pytest/service-desktop/test_calllog.py
A test/pytest/service-desktop/test_connection_security.py
M test/pytest/service-desktop/test_contacts.py
M test/pytest/service-desktop/test_device_info.py
M test/pytest/service-desktop/test_factory_reset.py
M test/pytest/service-desktop/test_messages.py
M test/pytest/service-desktop/test_templates.py
M test/pytest/service-desktop/test_threads.py
M test/pytest/service-desktop/test_update.py
M enabled_unittests => enabled_unittests +1 -0
@@ 225,6 225,7 @@ TESTS_LIST["catch2-service-desktop"]="
    DB Helpers test - json encoding (messages);
    Context class test;
    Endpoint Factory test;
    Secured Endpoint Factory test;
"
#---------
TESTS_LIST["catch2-service-desktop-endpoint-contacts"]="

M image/assets/lang/English.json => image/assets/lang/English.json +1 -0
@@ 404,6 404,7 @@
  "app_settings_security_wrong_passcode": "Wrong passcode!",
  "app_settings_security_passcode_changed_successfully": "Passcode changed successfully!",
  "app_settings_security_passcode_disabled": "Passcode disabled!",
  "app_settings_security_usb_passcode": "USB security",
  "app_settings_apn_settings_no_apns": "<text align='center' color='9'>No APNs yet.<p>Press <b>left arrow</b> to add new.</p></text>",
  "app_settings_apn_options": "Options",
  "app_settings_apn_options_delete": "Delete",

M image/user/db/settings_v2_002.sql => image/user/db/settings_v2_002.sql +1 -1
@@ 20,9 20,9 @@ INSERT OR IGNORE INTO settings_tab (path, value) VALUES
    ('gs_input_language', 'English'),
    ('gs_eula_accepted', '0'),
    ('gs_onboarding_done', '0'),
    ('gs_usb_security', '1');
    ('bt_state', '0'),
    ('bt_device_visibility', '0'),
    ('bt_device_name', 'PurePhone'),
    ('bt_bonded_devices', ''),
    ('battery_critical_level', '0');


D image/user/settings.db => image/user/settings.db +0 -0
M module-apps/Application.cpp => module-apps/Application.cpp +1 -0
@@ 733,4 733,5 @@ namespace app
    {
        return lockScreenPasscodeIsOn;
    }

} /* namespace app */

M module-apps/Application.hpp => module-apps/Application.hpp +19 -18
@@ 4,26 4,27 @@
#pragma once

#include "AsyncTask.hpp"
#include "Audio/AudioCommon.hpp"                        // for Volume, Play...
#include "Audio/Profiles/Profile.hpp"                   // for Profile, Pro...
#include "Audio/AudioCommon.hpp"      // for Volume, Play...
#include "Audio/Profiles/Profile.hpp" // for Profile, Pro...
#include "CallbackStorage.hpp"
#include "Service/Common.hpp"                           // for ReturnCodes
#include "Service/Message.hpp"                          // for MessagePointer
#include "Service/Service.hpp"                          // for Service
#include "SwitchData.hpp"                               // for SwitchData
#include "SystemManager/SystemManager.hpp"              // for SystemManager
#include "bsp/keyboard/key_codes.hpp"                   // for bsp
#include "gui/Common.hpp"                               // for ShowMode
#include "projdefs.h"                                   // for pdMS_TO_TICKS

#include "Service/Common.hpp"              // for ReturnCodes
#include "Service/Message.hpp"             // for MessagePointer
#include "Service/Service.hpp"             // for Service
#include "SwitchData.hpp"                  // for SwitchData
#include "SystemManager/SystemManager.hpp" // for SystemManager
#include "bsp/keyboard/key_codes.hpp"      // for bsp
#include "gui/Common.hpp"                  // for ShowMode
#include "projdefs.h"                      // for pdMS_TO_TICKS
#include <service-appmgr/ApplicationManifest.hpp>
#include <list>                                         // for list
#include <map>                                          // for allocator, map
#include <memory>                                       // for make_shared
#include <module-bsp/bsp/torch/torch.hpp>               // for State, State...
#include <stdint.h>                                     // for uint32_t
#include <string>                                       // for string
#include <utility>                                      // for move, pair
#include <vector>                                       // for vector
#include <list>                           // for list
#include <map>                            // for allocator, map
#include <memory>                         // for make_shared
#include <module-bsp/bsp/torch/torch.hpp> // for State, State...
#include <stdint.h>                       // for uint32_t
#include <string>                         // for string
#include <utility>                        // for move, pair
#include <vector>                         // for vector
#include "TopBarManager.hpp"
#include "WindowsFactory.hpp"
#include "WindowsStack.hpp"

M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +6 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApplicationDesktop.hpp"


@@ 51,6 51,11 @@ namespace app
            return actionHandled();
        });

        addActionReceiver(app::manager::actions::RequestScreenPasscode, [this](auto &&data) {
            lockHandler.handleScreenPasscodeRequest(std::move(data));
            return msgHandled();
        });

        addActionReceiver(app::manager::actions::RequestPuk, [this](auto &&data) {
            lockHandler.handlePasscodeRequest(gui::PinLock::LockType::SimPuk, std::move(data));
            return actionHandled();

M module-apps/application-desktop/ApplicationDesktop.hpp => module-apps/application-desktop/ApplicationDesktop.hpp +2 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 101,6 101,7 @@ namespace app
                     manager::actions::RequestPin,
                     manager::actions::RequestPuk,
                     manager::actions::RequestPinChange,
                     manager::actions::RequestScreenPasscode,
                     manager::actions::UnlockSim,
                     manager::actions::BlockSim,
                     manager::actions::ShowMMIResponse,

M module-apps/application-desktop/widgets/PinLockHandler.cpp => module-apps/application-desktop/widgets/PinLockHandler.cpp +25 -1
@@ 1,4 1,4 @@
//// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
//// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
//// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "PinLockHandler.hpp"


@@ 81,6 81,30 @@ namespace gui
        }
    }

    void PinLockHandler::handleScreenPasscodeRequest(app::manager::actions::ActionParamsPtr &&data) const
    {
        LOG_DEBUG("Handling ScreenPasscode action");

        auto params = static_cast<app::manager::actions::ScreenPasscodeParams *>(data.get());
        auto lock   = std::make_unique<gui::PinLock>(
            Store::GSM::SIM::NONE, PinLock::LockState::PasscodeRequired, PinLock::LockType::Screen);

        if (params->isCancel()) {
            app->switchWindow(app::window::name::desktop_main_window);
            return;
        }

        lock->onActivatedCallback = [this](PinLock::LockType type, const std::vector<unsigned int> &data) {
            app->bus.sendUnicast(std::make_shared<sdesktop::passcode::ScreenPasscodeUnlocked>(),
                                 service::name::service_desktop);
            app->switchWindow(app::window::name::desktop_main_window);
        };

        app->switchWindow(app::window::name::desktop_pin_lock,
                          gui::ShowMode::GUI_SHOW_INIT,
                          std::make_unique<gui::LockPhoneData>(std::move(lock)));
    }

    void PinLockHandler::handlePinChangeRequest(app::manager::actions::ActionParamsPtr &&data)
    {
        LOG_DEBUG("Handling RequestPinChange action");

M module-apps/application-desktop/widgets/PinLockHandler.hpp => module-apps/application-desktop/widgets/PinLockHandler.hpp +2 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 52,6 52,7 @@ namespace gui
        void handleSimBlocked(app::manager::actions::ActionParamsPtr &&data);
        void handleUnlockSim(app::manager::actions::ActionParamsPtr &&data);
        void handleCMEError(app::manager::actions::ActionParamsPtr &&data) const;
        void handleScreenPasscodeRequest(app::manager::actions::ActionParamsPtr &&data) const;

        [[nodiscard]] auto isScreenLocked() const noexcept -> bool
        {

M module-apps/application-settings-new/ApplicationSettings.cpp => module-apps/application-settings-new/ApplicationSettings.cpp +24 -1
@@ 60,6 60,8 @@
#include <module-services/service-evtmgr/service-evtmgr/EVMessages.hpp>
#include <module-services/service-appmgr/service-appmgr/messages/Message.hpp>
#include <module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp>
#include <module-apps/application-desktop/windows/PinLockWindow.hpp>
#include <module-apps/application-desktop/windows/Names.hpp>

namespace app
{


@@ 222,6 224,13 @@ namespace app
            },
            ::settings::SettingsScope::Global);

        /*
        settings->registerValueChange(
            ::settings::SystemProperties::usbSecurity,
            [this](std::string value) { usbSecured = utils::getNumericValue<bool>(value); },
            ::settings::SettingsScope::Global);
        */

        return ret;
    }



@@ 296,7 305,10 @@ namespace app
            return std::make_unique<gui::DialogYesNo>(app, name);
        });
        windowsFactory.attach(gui::window::name::security, [](Application *app, const std::string &name) {
            return std::make_unique<gui::SecurityMainWindow>(app);
            return std::make_unique<gui::SecurityMainWindow>(app, static_cast<ApplicationSettingsNew *>(app));
        });
        windowsFactory.attach(app::window::name::desktop_pin_lock, [&](Application *app, const std::string newname) {
            return std::make_unique<gui::PinLockWindow>(app, app::window::name::desktop_pin_lock);
        });
        windowsFactory.attach(gui::window::name::change_passcode, [](Application *app, const std::string &name) {
            return std::make_unique<gui::ChangePasscodeWindow>(app);


@@ 459,4 471,15 @@ namespace app
                        service::name::evt_manager);
    }

    bool ApplicationSettingsNew::isUSBSecured() const
    {
        return usbSecured;
    }

    void ApplicationSettingsNew::setUSBSecurity(bool security)
    {
        usbSecured = security;
        settings->setValue(
            ::settings::SystemProperties::usbSecurity, std::to_string(security), ::settings::SettingsScope::Global);
    }
} /* namespace app */

M module-apps/application-settings-new/ApplicationSettings.hpp => module-apps/application-settings-new/ApplicationSettings.hpp +19 -1
@@ 112,13 112,23 @@ namespace app
            virtual void setKeypadBacklightState(bool newState) = 0;
        };

        class SecuritySettings
        {
          public:
            virtual ~SecuritySettings() = default;

            virtual auto isUSBSecured() const -> bool  = 0;
            virtual void setUSBSecurity(bool security) = 0;
        };

    }; // namespace settingsInterface

    class ApplicationSettingsNew : public app::Application,
                                   public settingsInterface::SimParams,
                                   public settingsInterface::OperatorsSettings,
                                   public settingsInterface::ScreenLightSettings,
                                   public settingsInterface::KeypdBacklightSettings
                                   public settingsInterface::KeypdBacklightSettings,
                                   public settingsInterface::SecuritySettings
    {
      public:
        ApplicationSettingsNew(std::string name                    = name_settings_new,


@@ 159,6 169,12 @@ namespace app
        auto isKeypadBacklightOn() -> bool override;
        void setKeypadBacklightState(bool newState) override;

        auto isUSBSecured() const -> bool override;
        void setUSBSecurity(bool security) override;

        void setLockScreenPasscodeOn(bool passcodeOn);
        auto isLockScreenPasscodeOn() const -> bool;

      private:
        void attachQuotesWindows();



@@ 167,6 183,8 @@ namespace app
        bsp::Board board              = bsp::Board::none;
        bool operatorsOn              = false;
        bool voLteStateOn             = false;
        bool usbSecured               = true;
        bool lockScreenPasscodeOn     = true;
        unsigned int lockPassHash     = 0;
    };


M module-apps/application-settings-new/windows/SecurityMainWindow.cpp => module-apps/application-settings-new/windows/SecurityMainWindow.cpp +33 -3
@@ 1,16 1,18 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/data/ChangePasscodeData.hpp"
#include "module-apps/application-desktop/windows/Names.hpp"
#include "module-apps/application-desktop/data/LockPhoneData.hpp"
#include "OptionSetting.hpp"
#include "SecurityMainWindow.hpp"

namespace gui
{
    SecurityMainWindow::SecurityMainWindow(app::Application *app)
        : BaseSettingsWindow(app, window::name::security), lockScreenPasscodeIsOn(app->isLockScreenPasscodeOn())
    SecurityMainWindow::SecurityMainWindow(app::Application *app, app::settingsInterface::SecuritySettings *settings)
        : BaseSettingsWindow(app, window::name::security), lockScreenPasscodeIsOn(app->isLockScreenPasscodeOn()),
          securitySettings(settings)
    {}

    auto SecurityMainWindow::buildOptionsList() -> std::list<Option>


@@ 42,6 44,34 @@ namespace gui
            nullptr,
            lockScreenPasscodeIsOn ? option::SettingRightItem::On : option::SettingRightItem::Off));

        optionList.emplace_back(std::make_unique<option::OptionSettings>(
            utils::translateI18("app_settings_security_usb_passcode"),
            [=](Item &item) {
                auto lock = std::make_unique<gui::PinLock>(
                    Store::GSM::SIM::NONE, PinLock::LockState::PasscodeRequired, PinLock::LockType::Screen);
                lock->onActivatedCallback = [this](PinLock::LockType type, const std::vector<unsigned int> &data) {
                    securitySettings->setUSBSecurity(!securitySettings->isUSBSecured());
                    application->returnToPreviousWindow();
                };
                application->switchWindow(app::window::name::desktop_pin_lock,
                                          gui::ShowMode::GUI_SHOW_INIT,
                                          std::make_unique<gui::LockPhoneData>(std::move(lock)));
                return true;
            },
            [=](Item &item) {
                if (item.focus) {
                    this->setBottomBarText(utils::localize.get(style::strings::common::Switch),
                                           BottomBar::Side::CENTER);
                }
                else {
                    this->setBottomBarText(utils::localize.get(style::strings::common::select),
                                           BottomBar::Side::CENTER);
                }
                return true;
            },
            nullptr,
            securitySettings->isUSBSecured() ? option::SettingRightItem::On : option::SettingRightItem::Off));

        if (lockScreenPasscodeIsOn) {
            optionList.emplace_back(std::make_unique<option::OptionSettings>(
                utils::translateI18("app_settings_security_change_passcode"),

M module-apps/application-settings-new/windows/SecurityMainWindow.hpp => module-apps/application-settings-new/windows/SecurityMainWindow.hpp +3 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 10,11 10,12 @@ namespace gui
    class SecurityMainWindow : public BaseSettingsWindow
    {
      public:
        explicit SecurityMainWindow(app::Application *app);
        explicit SecurityMainWindow(app::Application *app, app::settingsInterface::SecuritySettings *settings);

      private:
        auto buildOptionsList() -> std::list<Option> override;

        bool lockScreenPasscodeIsOn;
        app::settingsInterface::SecuritySettings *securitySettings;
    };
} // namespace gui

M module-bsp/board/linux/usb_cdc/usb_cdc.cpp => module-bsp/board/linux/usb_cdc/usb_cdc.cpp +32 -2
@@ 6,6 6,9 @@
#include <fcntl.h>
#include <fstream>
#include <string>
#include <sys/inotify.h>
#include <array>
#include <limits.h>

#ifndef DEUBG_USB
#undef LOG_PRINTF


@@ 29,8 32,11 @@
namespace bsp
{
    int fd;
    int fdNofity;
    xQueueHandle USBReceiveQueue;
    xQueueHandle USBIrqQueue;
    constexpr auto ptsFileName = "/tmp/purephone_pts_name";
    char *pts_name             = NULL;

#if USBCDC_ECHO_ENABLED
    bool usbCdcEchoEnabled = false;


@@ 47,12 53,32 @@ namespace bsp
        usbCDCReceive(ptr);
    }

    void checkUsbStatus()
    {
        char eventsBuff[((sizeof(inotify_event) + NAME_MAX + 1))];
        int len = read(fdNofity, eventsBuff, ((sizeof(inotify_event) + NAME_MAX + 1)));
        if (len > 0) {
            const inotify_event *event = (inotify_event *)&eventsBuff[0];
            if (event->mask & IN_OPEN) {
                USBDeviceStatus notification = USBDeviceStatus::Connected;
                xQueueSend(USBIrqQueue, &notification, 0);
            }
            if (event->mask & IN_CLOSE_WRITE) {
                USBDeviceStatus notification = USBDeviceStatus::Disconnected;
                xQueueSend(USBIrqQueue, &notification, 0);
            }
        }
    }

    int usbCDCReceive(void *)
    {
        LOG_INFO("[ServiceDesktop:BSP_Driver] Start reading on fd:%d", fd);
        char inputData[SERIAL_BUFFER_LEN];

        while (1) {

            checkUsbStatus();

            if (uxQueueSpacesAvailable(USBReceiveQueue) != 0) {
                memset(inputData, 0, SERIAL_BUFFER_LEN);



@@ 124,7 150,7 @@ namespace bsp
        std::remove(ptsFileName);
    }

    int usbInit(xQueueHandle receiveQueue, USBDeviceListener *)
    int usbInit(xQueueHandle receiveQueue, xQueueHandle irqQueue, USBDeviceListener *)
    {

        fd = 0;


@@ 137,12 163,15 @@ namespace bsp
        grantpt(fd);
        unlockpt(fd);

        char *pts_name = ptsname(fd);
        pts_name = ptsname(fd);
        if (pts_name == nullptr) {
            LOG_ERROR("bsp::usbInit ptsname returned NULL, no pseudo terminal allocated");
            return -1;
        }

        fdNofity = inotify_init1(O_NONBLOCK);
        inotify_add_watch(fdNofity, pts_name, IN_OPEN | IN_CLOSE_WRITE);

        writePtsToFile(pts_name);
        LOG_INFO("bsp::usbInit linux ptsname: %s", pts_name);
        struct termios newtio;


@@ 165,6 194,7 @@ namespace bsp

        xTaskHandle taskHandleReceive;
        USBReceiveQueue = receiveQueue;
        USBIrqQueue     = irqQueue;

        BaseType_t task_error = xTaskCreate(&bsp::usbDeviceTask,
                                            "USBLinuxReceive",

M module-bsp/board/rt1051/bsp/usb => module-bsp/board/rt1051/bsp/usb +1 -1
@@ 1,1 1,1 @@
Subproject commit 79c274b8ab4c8d146c6c9f677fe98eda25e181a5
Subproject commit ed8055cf9a7160772ab502b938689088e83f59b1

M module-bsp/bsp/usb/usb.hpp => module-bsp/bsp/usb/usb.hpp +15 -4
@@ 1,3 1,6 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

extern "C"


@@ 15,19 18,27 @@ extern "C"
#include <unistd.h>

inline constexpr auto SERIAL_BUFFER_LEN = 512;
inline constexpr auto  SERIAL_BAUDRATE = 115200;
inline constexpr auto SERIAL_BAUDRATE   = 115200;

namespace bsp
{
    class USBDeviceListener {
    enum class USBDeviceStatus : uint32_t
    {
        Disconnected,
        Connected
    };

    class USBDeviceListener
    {
      public:
        virtual bool getRawMode() const noexcept{
        virtual bool getRawMode() const noexcept
        {
            return false;
        }
        virtual void rawDataReceived(void *dataPtr, uint32_t dataLen) = 0;
    };

    int usbInit(xQueueHandle, USBDeviceListener *deviceListener = nullptr);
    int usbInit(xQueueHandle, xQueueHandle, USBDeviceListener *deviceListener = nullptr);
    int usbCDCReceive(void *ptr);
    int usbCDCSend(std::string *sendMsg);
    int usbCDCSendRaw(const char *dataPtr, size_t dataLen);

M module-services/service-appmgr/CMakeLists.txt => module-services/service-appmgr/CMakeLists.txt +1 -0
@@ 4,6 4,7 @@ message( "${PROJECT_NAME}  ${CMAKE_CURRENT_LIST_DIR}" )
set(SOURCES
    ApplicationManifest.cpp
    Controller.cpp
    data/UsbActionsParams.cpp
    data/SimActionsParams.cpp
    data/MmiActionsParams.cpp
    model/ApplicationManager.cpp

A module-services/service-appmgr/data/UsbActionsParams.cpp => module-services/service-appmgr/data/UsbActionsParams.cpp +23 -0
@@ 0,0 1,23 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <service-appmgr/data/UsbActionsParams.hpp>

using namespace app::manager::actions;

ScreenPasscodeParams::ScreenPasscodeParams(bool cancel, unsigned int _attempts, std::string _passcodeName)
    : cancel(cancel), attempts{_attempts}, passcodeName{std::move(_passcodeName)}
{}

unsigned int ScreenPasscodeParams::getAttempts() const noexcept
{
    return attempts;
}
const std::string &ScreenPasscodeParams::getPasscodeName() const noexcept
{
    return passcodeName;
}
bool ScreenPasscodeParams::isCancel() const noexcept
{
    return cancel;
}

M module-services/service-appmgr/model/ApplicationManager.cpp => module-services/service-appmgr/model/ApplicationManager.cpp +2 -0
@@ 20,6 20,7 @@
#include <service-gui/ServiceGUI.hpp>
#include <service-eink/ServiceEink.hpp>
#include <service-gui/Common.hpp>
#include <service-desktop/DesktopMessages.hpp>

#include <algorithm>
#include <limits>


@@ 317,6 318,7 @@ namespace app::manager
        connect(typeid(sys::CriticalBatteryLevelNotification), convertibleToActionHandler);
        connect(typeid(sys::SystemBrownoutMesssage), convertibleToActionHandler);
        connect(typeid(CellularSmsNoSimRequestMessage), convertibleToActionHandler);
        connect(typeid(sdesktop::passcode::ScreenPasscodeRequest), convertibleToActionHandler);
    }

    sys::ReturnCodes ApplicationManager::SwitchPowerModeHandler(const sys::ServicePowerMode mode)

M module-services/service-appmgr/service-appmgr/Actions.hpp => module-services/service-appmgr/service-appmgr/Actions.hpp +1 -0
@@ 54,6 54,7 @@ namespace app::manager
            DisplayCMEError,
            DisplayLowBatteryNotification,
            SystemBrownout,
            RequestScreenPasscode,
            UserAction // The last enumerator in the Action enum.
                       // All user-defined actions shall have values greater than UserAction.
                       // All system-wide actions shall have values lesser than UserAction.

A module-services/service-appmgr/service-appmgr/data/UsbActionsParams.hpp => module-services/service-appmgr/service-appmgr/data/UsbActionsParams.hpp +27 -0
@@ 0,0 1,27 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <service-appmgr/service-appmgr/Actions.hpp>
#include <module-utils/common_data/EventStore.hpp>

namespace app::manager::actions
{
    /** Action parameters for
     * RequestScreenPasscode
     */
    class ScreenPasscodeParams : public ActionParams
    {
        bool cancel           = false;
        unsigned int attempts = 0;
        std::string passcodeName;

      public:
        ScreenPasscodeParams(bool cancel, unsigned int _attempts = 0, std::string _passcodeName = "Screen");

        [[nodiscard]] unsigned int getAttempts() const noexcept;
        [[nodiscard]] const std::string &getPasscodeName() const noexcept;
        [[nodiscard]] bool isCancel() const noexcept;
    };
} // namespace app::manager::actions

M module-services/service-db/agents/settings/SystemSettings.hpp => module-services/service-db/agents/settings/SystemSettings.hpp +1 -0
@@ 9,6 9,7 @@ namespace settings
    {
        constexpr inline auto activeSim                = "gs_active_sim";
        constexpr inline auto lockPassHash             = "gs_lock_pass_hash";
        constexpr inline auto usbSecurity              = "gs_usb_security";
        constexpr inline auto lockScreenPasscodeIsOn   = "gs_lock_screen_passcode_is_on";
        constexpr inline auto lockTime                 = "gs_lock_time";
        constexpr inline auto displayLanguage          = "gs_display_language";

M module-services/service-desktop/ServiceDesktop.cpp => module-services/service-desktop/ServiceDesktop.cpp +43 -4
@@ 23,6 23,8 @@

#include <cinttypes>
#include <filesystem>
#include <module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp>
#include <module-services/service-db/agents/settings/SystemSettings.hpp>

#include <purefs/filesystem_paths.hpp>
#include <sys/mount.h>


@@ 69,10 71,11 @@ ServiceDesktop::~ServiceDesktop()

sys::ReturnCodes ServiceDesktop::InitHandler()
{
    desktopWorker  = std::make_unique<WorkerDesktop>(this);
    const bool ret = desktopWorker->init(
        {{sdesktop::RECEIVE_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_len},
         {sdesktop::SEND_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_object_size}});
    desktopWorker = std::make_unique<WorkerDesktop>(this);
    const bool ret =
        desktopWorker->init({{sdesktop::RECEIVE_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_len},
                             {sdesktop::SEND_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_object_size},
                             {sdesktop::IRQ_QUEUE_BUFFER_NAME, 1, sdesktop::irq_queue_object_size}});

    if (ret == false) {
        LOG_ERROR("!!! service-desktop InitHandler failed to initialize worker, service-desktop won't work");


@@ 183,9 186,45 @@ sys::ReturnCodes ServiceDesktop::InitHandler()
        return std::make_shared<sys::ResponseMessage>();
    });

    connect(sdesktop::usb::USBConnected(), [&](sys::Message *msg) {
        if (!desktopWorker->isEndpointSecurityEnabled()) {
            LOG_INFO("Endpoint security disabled.");
            return std::make_shared<sys::ResponseMessage>();
        }

        LOG_INFO("USB connected with endpoint security enabled. Requesting passcode.");
        desktopWorker->setEndpointSecurity(EndpointSecurity::Block);
        bus.sendUnicast(std::make_shared<sdesktop::passcode::ScreenPasscodeRequest>(),
                        app::manager::ApplicationManager::ServiceName);

        return std::make_shared<sys::ResponseMessage>();
    });

    connect(sdesktop::usb::USBDisconnected(), [&](sys::Message *msg) {
        bus.sendUnicast(std::make_shared<sdesktop::passcode::ScreenPasscodeRequest>(),
                        app::manager::ApplicationManager::ServiceName);
        return std::make_shared<sys::ResponseMessage>();
    });

    connect(sdesktop::passcode::ScreenPasscodeUnlocked(), [&](sys::Message *msg) {
        LOG_INFO("Passcode accepted. Enabling secured endpoints.");
        desktopWorker->setEndpointSecurity(EndpointSecurity::Allow);
        return std::make_shared<sys::ResponseMessage>();
    });

    settings->registerValueChange(updateos::settings::history,
                                  [this](const std::string &value) { updateOS->setInitialHistory(value); });

    settings->registerValueChange(
        ::settings::SystemProperties::usbSecurity,
        [this](std::string value) {
            bool securityEnabled = utils::getNumericValue<bool>(value);
            LOG_INFO("Setting endpoint security: %d", securityEnabled);
            desktopWorker->enableEndpointSecurity(securityEnabled);
            desktopWorker->setEndpointSecurity(securityEnabled ? EndpointSecurity::Block : EndpointSecurity::Allow);
        },
        settings::SettingsScope::Global);

    return (sys::ReturnCodes::Success);
}


M module-services/service-desktop/WorkerDesktop.cpp => module-services/service-desktop/WorkerDesktop.cpp +30 -6
@@ 3,6 3,7 @@

#include "service-desktop/ServiceDesktop.hpp"
#include "service-desktop/WorkerDesktop.hpp"
#include "service-desktop/endpoints/EndpointFactory.hpp"
#include "service-desktop/DesktopMessages.hpp"
#include "parser/MessageHandler.hpp"
#include "parser/ParserFSM.hpp"


@@ 10,27 11,26 @@

#include <bsp/usb/usb.hpp>
#include <log/log.hpp>
#include <projdefs.h>
#include <queue.h>

#include <map>
#include <vector>
#include <module-services/service-desktop/service-desktop/DesktopMessages.hpp>

inline constexpr auto uploadFailedMessage = "file upload terminated before all data transferred";

WorkerDesktop::WorkerDesktop(sys::Service *ownerServicePtr)
    : sys::Worker(ownerServicePtr), ownerService(ownerServicePtr), parser(ownerServicePtr), fileDes(nullptr)
{
}
{}

bool WorkerDesktop::init(std::list<sys::WorkerQueueInfo> queues)
{
    Worker::init(queues);

    receiveQueue                         = Worker::getQueueHandleByName(sdesktop::RECEIVE_QUEUE_BUFFER_NAME);
    irqQueue     = Worker::getQueueHandleByName(sdesktop::IRQ_QUEUE_BUFFER_NAME);
    receiveQueue = Worker::getQueueHandleByName(sdesktop::RECEIVE_QUEUE_BUFFER_NAME);
    parserFSM::MessageHandler::setSendQueueHandle(Worker::getQueueHandleByName(sdesktop::SEND_QUEUE_BUFFER_NAME));

    return (bsp::usbInit(receiveQueue, this) < 0) ? false : true;
    return (bsp::usbInit(receiveQueue, irqQueue, this) < 0) ? false : true;
}

bool WorkerDesktop::deinit(void)


@@ 62,7 62,13 @@ bool WorkerDesktop::handleMessage(uint32_t queueID)
            LOG_ERROR("handleMessage failed to receive from \"%s\"", sdesktop::RECEIVE_QUEUE_BUFFER_NAME);
            return false;
        }

        auto factory = std::make_unique<SecuredEndpointFactory>(endpointSecurity);
        auto handler = std::make_unique<parserFSM::MessageHandler>(ownerService, std::move(factory));

        parser.setMessageHandler(std::move(handler));
        parser.processMessage(std::move(*receivedMsg));

        delete receivedMsg;
    }
    else if (qname == sdesktop::SEND_QUEUE_BUFFER_NAME) {


@@ 91,6 97,24 @@ bool WorkerDesktop::handleMessage(uint32_t queueID)
            return false;
        }
    }
    else if (qname == sdesktop::IRQ_QUEUE_BUFFER_NAME) {
        bsp::USBDeviceStatus notification = bsp::USBDeviceStatus::Disconnected;
        if (!queue->Dequeue(&notification, 0)) {
            LOG_ERROR("handleMessage xQueueReceive failed for %s.", sdesktop::IRQ_QUEUE_BUFFER_NAME);
            return false;
        }

        LOG_DEBUG("USB status: %d", static_cast<int>(notification));

        if (notification == bsp::USBDeviceStatus::Connected) {
            ownerService->bus.sendUnicast(std::make_shared<sdesktop::usb::USBConnected>(),
                                          service::name::service_desktop);
        }
        else if (notification == bsp::USBDeviceStatus::Disconnected) {
            ownerService->bus.sendUnicast(std::make_shared<sdesktop::usb::USBDisconnected>(),
                                          service::name::service_desktop);
        }
    }
    else {
        LOG_INFO("handeMessage got message on an unhandled queue");
    }

M module-services/service-desktop/endpoints/Endpoint.hpp => module-services/service-desktop/endpoints/Endpoint.hpp +17 -2
@@ 5,6 5,7 @@

#include "Context.hpp"
#include <parser/ParserUtils.hpp>
#include <parser/MessageHandler.hpp>

#include <json/json11.hpp>
#include <Common/Query.hpp>


@@ 17,10 18,9 @@ namespace parserFSM

    class Endpoint
    {

      public:
        Endpoint(sys::Service *_ownerServicePtr) : ownerServicePtr(_ownerServicePtr){};
        virtual ~Endpoint()                           = default;
        virtual ~Endpoint()                                      = default;
        virtual auto handle(parserFSM::Context &context) -> void = 0;
        auto c_str() -> const char *
        {


@@ 32,4 32,19 @@ namespace parserFSM
        sys::Service *ownerServicePtr = nullptr;
    };

    class SecuredEndpoint : public Endpoint
    {
      public:
        explicit SecuredEndpoint(sys::Service *ownerServicePtr) : Endpoint(ownerServicePtr)
        {}
        ~SecuredEndpoint() = default;

        auto handle(Context &context) -> void override
        {
            context.setResponseStatus(http::Code::Forbidden);
            MessageHandler::putToSendQueue(context.createSimpleResponse());
            LOG_INFO("Endpoint #%d secured", static_cast<int>(context.getEndpoint()));
        }
    };

} // namespace parserFSM

M module-services/service-desktop/endpoints/EndpointFactory.hpp => module-services/service-desktop/endpoints/EndpointFactory.hpp +36 -1
@@ 23,7 23,8 @@
class EndpointFactory
{
  public:
    static auto create(parserFSM::Context &context, sys::Service *ownerServicePtr)
    virtual ~EndpointFactory() = default;
    virtual auto create(parserFSM::Context &context, sys::Service *ownerServicePtr)
        -> std::unique_ptr<parserFSM::Endpoint>
    {
        LOG_DEBUG("Creating endpoint: %d", static_cast<int>(context.getEndpoint()));


@@ 57,3 58,37 @@ class EndpointFactory
        }
    }
};

enum class EndpointSecurity
{
    Allow = 0,
    Block = 1
};

class SecuredEndpointFactory : public EndpointFactory
{
    static constexpr auto Whitelist = {parserFSM::EndpointType::developerMode};

  public:
    explicit SecuredEndpointFactory(EndpointSecurity security) : endpointSecurity(security)
    {}

    auto create(parserFSM::Context &context, sys::Service *ownerServicePtr)
        -> std::unique_ptr<parserFSM::Endpoint> override
    {
        auto security = endpointSecurity;
        if (std::find(Whitelist.begin(), Whitelist.end(), context.getEndpoint()) != Whitelist.end()) {
            security = EndpointSecurity::Allow;
        }

        switch (security) {
        case EndpointSecurity::Allow:
            return EndpointFactory::create(context, ownerServicePtr);
        default:
            return std::make_unique<parserFSM::SecuredEndpoint>(ownerServicePtr);
        }
    }

  private:
    EndpointSecurity endpointSecurity;
};

M module-services/service-desktop/endpoints/backup/BackupEndpoint.hpp => module-services/service-desktop/endpoints/backup/BackupEndpoint.hpp +1 -2
@@ 1,11 1,10 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <endpoints/Endpoint.hpp>
#include <parser/ParserUtils.hpp>
#include <service-desktop/ServiceDesktop.hpp>

#include <Service/Common.hpp>


M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp +13 -2
@@ 103,6 103,17 @@ auto DeveloperModeHelper::processPut(Context &context) -> ProcessResult
                               service::name::system_manager);
        return {sent::delayed, std::nullopt};
    }
    else if (body[json::developerMode::usbSecurity].is_string()) {
        std::shared_ptr<sys::DataMessage> msg = std::make_shared<sdesktop::usb::USBConnected>();
        if (body[json::developerMode::usbSecurity].string_value() == json::developerMode::usbUnlock) {
            msg = std::make_shared<sdesktop::passcode::ScreenPasscodeUnlocked>();
        }
        code = toCode(owner->bus.sendUnicast(std::move(msg), "ServiceDesktop"));
    }
    else {
        context.setResponseStatus(http::Code::BadRequest);
        MessageHandler::putToSendQueue(context.createSimpleResponse());
    }
    return {sent::no, endpoint::ResponseContext{.status = code}};
}



@@ 237,8 248,8 @@ auto DeveloperModeHelper::smsRecordFromJson(json11::Json msgJson) -> SMSRecord
    record.type = static_cast<SMSType>(msgJson[json::messages::messageType].int_value());
    utils::PhoneNumber phoneNumber(msgJson[json::messages::phoneNumber].string_value());
    record.number = phoneNumber.getView();
    record.date = utils::time::getCurrentTimestamp().getTime();
    record.body = UTF8(msgJson[json::messages::messageBody].string_value());
    record.date   = utils::time::getCurrentTimestamp().getTime();
    record.body   = UTF8(msgJson[json::messages::messageBody].string_value());
    return record;
}


M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.hpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.hpp +11 -1
@@ 56,6 56,8 @@ namespace parserFSM
        inline constexpr auto getInfo                = "getInfo";
        inline constexpr auto tethering              = "tethering";

        inline constexpr auto tethering   = "tethering";
        inline constexpr auto usbSecurity = "usbSecurity";
        /// values for getInfo cmd
        inline constexpr auto simStateInfo      = "simState";
        inline constexpr auto cellularStateInfo = "cellularState";


@@ 66,5 68,13 @@ namespace parserFSM
        /// values for tethering
        inline constexpr auto tetheringOn  = "on";
        inline constexpr auto tetheringOff = "off";
    }

        /// values for tethering
        inline constexpr auto tetheringOn  = "on";
        inline constexpr auto tetheringOff = "off";
    } // namespace json::developerMode

    /// values for usbSecurity
    inline constexpr auto usbLock   = "usbLock";
    inline constexpr auto usbUnlock = "usbUnlock";
} // namespace parserFSM

M module-services/service-desktop/endpoints/restore/RestoreEndpoint.hpp => module-services/service-desktop/endpoints/restore/RestoreEndpoint.hpp +3 -2
@@ 1,9 1,10 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <endpoints/Endpoint.hpp>
#include <parser/ParserUtils.hpp>
#include <service-desktop/ServiceDesktop.hpp>

#include <string>


M module-services/service-desktop/parser/HttpEnums.hpp => module-services/service-desktop/parser/HttpEnums.hpp +1 -0
@@ 14,6 14,7 @@ namespace parserFSM::http
        OK                  = 200,
        Accepted            = 202,
        BadRequest          = 400,
        Forbidden           = 403,
        NotAcceptable       = 406,
        InternalServerError = 500
    };

M module-services/service-desktop/parser/MessageHandler.cpp => module-services/service-desktop/parser/MessageHandler.cpp +7 -4
@@ 4,7 4,6 @@
#include "MessageHandler.hpp"

#include <endpoints/Context.hpp>
#include <endpoints/Endpoint.hpp>
#include <endpoints/EndpointFactory.hpp>

#include <FreeRTOS.h>


@@ 23,10 22,14 @@ using namespace parserFSM;

xQueueHandle MessageHandler::sendQueue;

MessageHandler::MessageHandler(const std::string &message, sys::Service *OwnerService) : OwnerServicePtr(OwnerService)
MessageHandler::MessageHandler(sys::Service *OwnerService, std::unique_ptr<EndpointFactory> endpointFactory)
    : OwnerServicePtr(OwnerService), endpointFactory(std::move(endpointFactory))
{}

void MessageHandler::parseMessage(const std::string &msg)
{
    try {
        messageJson = json11::Json::parse(message, JsonErrorMsg);
        messageJson = json11::Json::parse(msg, JsonErrorMsg);
    }
    catch (const std::exception &e) {
        LOG_ERROR("Cannot create MessageHandler! err:%s", e.what());


@@ 43,7 46,7 @@ void MessageHandler::processMessage()
              context->getUuid(),
              context->getBody().dump().c_str());

    auto handler = EndpointFactory::create(*context, OwnerServicePtr);
    auto handler = endpointFactory->create(*context, OwnerServicePtr);

    if (handler != nullptr) {
        handler->handle(*context);

M module-services/service-desktop/parser/MessageHandler.hpp => module-services/service-desktop/parser/MessageHandler.hpp +6 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 20,6 20,8 @@ extern "C"
#include <queue.h>
}

class EndpointFactory;

namespace parserFSM
{
    class MessageHandler


@@ 29,9 31,10 @@ namespace parserFSM
        json11::Json messageJson;
        std::string JsonErrorMsg;
        sys::Service *OwnerServicePtr = nullptr;
        std::unique_ptr<EndpointFactory> endpointFactory;

      public:
        MessageHandler(const std::string &message, sys::Service *OwnerService);
        MessageHandler(sys::Service *OwnerService, std::unique_ptr<EndpointFactory> endpointFactory);

        [[nodiscard]] auto isJSONNull() const -> bool
        {


@@ 45,6 48,7 @@ namespace parserFSM
        {
            return JsonErrorMsg;
        };
        void parseMessage(const std::string &msg);
        void processMessage();
        static void putToSendQueue(const std::string &msg);
        static void setSendQueueHandle(xQueueHandle handle)

M module-services/service-desktop/parser/ParserFSM.cpp => module-services/service-desktop/parser/ParserFSM.cpp +10 -6
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "MessageHandler.hpp"


@@ 161,14 161,18 @@ void StateMachine::parsePayload()

    state = State::ReceivedPayload;

    // processing payload
    auto handler = std::make_unique<MessageHandler>(payload, OwnerServicePtr);
    messageHandler->parseMessage(payload);

    if (!handler->isValid() || handler->isJSONNull()) {
        LOG_DEBUG("JsonErr: %s", handler->getErrorString().c_str());
    if (!messageHandler->isValid() || messageHandler->isJSONNull()) {
        LOG_DEBUG("JsonErr: %s", messageHandler->getErrorString().c_str());
        state = State::NoMsg;
        return;
    }

    handler->processMessage();
    messageHandler->processMessage();
}

void StateMachine::setMessageHandler(std::unique_ptr<MessageHandler> handler)
{
    messageHandler = std::move(handler);
}

M module-services/service-desktop/parser/ParserFSM.hpp => module-services/service-desktop/parser/ParserFSM.hpp +4 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 35,6 35,8 @@ namespace parserFSM
            state = newState;
        }

        void setMessageHandler(std::unique_ptr<MessageHandler> handler);

      private:
        std::string receivedMsg;
        parserFSM::State state = State::NoMsg;


@@ 42,6 44,7 @@ namespace parserFSM
        std::string header;
        unsigned long payloadLength   = 0;
        sys::Service *OwnerServicePtr = nullptr;
        std::unique_ptr<MessageHandler> messageHandler;

        void parseHeader();
        void parsePartialHeader();

M module-services/service-desktop/service-desktop/DesktopMessages.hpp => module-services/service-desktop/service-desktop/DesktopMessages.hpp +55 -0
@@ 7,6 7,10 @@
#include <endpoints/bluetooth/BluetoothEndpoint.hpp>
#include <endpoints/update/UpdateMuditaOS.hpp>

#include <service-appmgr/Actions.hpp>
#include <service-appmgr/messages/ActionRequest.hpp>
#include <service-appmgr/data/SimActionsParams.hpp>
#include <service-appmgr/data/UsbActionsParams.hpp>
#include <Service/Message.hpp>
#include <MessageType.hpp>
#include <service-desktop/DeveloperModeMessage.hpp>


@@ 67,6 71,57 @@ namespace sdesktop
        ~FactoryMessage() override = default;
    };

    namespace usb
    {
        class USBConnected : public sys::DataMessage
        {
          public:
            USBConnected() : sys::DataMessage(MessageType::USBConnected)
            {}
            ~USBConnected() override = default;
        };

        class USBDisconnected : public sys::DataMessage
        {
          public:
            USBDisconnected() : sys::DataMessage(MessageType::USBDisconnected)
            {}
            ~USBDisconnected() override = default;
        };

    } // namespace usb

    namespace passcode
    {
        class ScreenPasscodeRequest : public sys::DataMessage, public app::manager::actions::ConvertibleToAction
        {
            static constexpr auto passcodeName = "ScreenPasscode";

          public:
            explicit ScreenPasscodeRequest(bool cancel = false)
                : sys::DataMessage(MessageType::ScreenPasscodeRequest), cancel(cancel)
            {}

            [[nodiscard]] auto toAction() const -> std::unique_ptr<app::manager::ActionRequest>
            {
                return std::make_unique<app::manager::ActionRequest>(
                    sender,
                    app::manager::actions::RequestScreenPasscode,
                    std::make_unique<app::manager::actions::ScreenPasscodeParams>(cancel));
            }

          private:
            bool cancel = false;
        };

        class ScreenPasscodeUnlocked : public sys::DataMessage
        {
          public:
            explicit ScreenPasscodeUnlocked() : sys::DataMessage(MessageType::ScreenPasscodeUnlocked)
            {}
        }; // namespace sdesktop
    }      // namespace passcode

    namespace developerMode
    {


M module-services/service-desktop/service-desktop/ServiceDesktop.hpp => module-services/service-desktop/service-desktop/ServiceDesktop.hpp +4 -1
@@ 22,12 22,15 @@ namespace settings

namespace sdesktop
{
    inline constexpr auto service_stack         = 8192;
    inline constexpr auto service_stack             = 8192;
    inline constexpr auto cdc_queue_len             = 32;
    inline constexpr auto cdc_queue_object_size     = 1024;
    inline constexpr auto irq_queue_object_size     = sizeof(bsp::USBDeviceStatus);
    inline constexpr auto file_transfer_timeout     = 5000;
    inline constexpr auto RECEIVE_QUEUE_BUFFER_NAME = "receiveQueueBuffer";
    inline constexpr auto SEND_QUEUE_BUFFER_NAME    = "sendQueueBuffer";
    inline constexpr auto IRQ_QUEUE_BUFFER_NAME     = "irqQueueBuffer";

}; // namespace sdesktop

class ServiceDesktop : public sys::Service

M module-services/service-desktop/service-desktop/WorkerDesktop.hpp => module-services/service-desktop/service-desktop/WorkerDesktop.hpp +21 -3
@@ 1,10 1,8 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <string.h>
#include <stdio.h>
#include <filesystem>
#include <atomic>
#include "Service/Message.hpp"


@@ 12,6 10,7 @@
#include "Service/Worker.hpp"
#include "Service/Timer.hpp"
#include "parser/ParserFSM.hpp"
#include "endpoints/EndpointFactory.hpp"
#include "bsp/usb/usb.hpp"

class WorkerDesktop : public sys::Worker, public bsp::USBDeviceListener


@@ 26,6 25,7 @@ class WorkerDesktop : public sys::Worker, public bsp::USBDeviceListener
    {
        CancelTransfer,
    };

    WorkerDesktop(sys::Service *ownerServicePtr);

    virtual bool init(std::list<sys::WorkerQueueInfo> queues) override;


@@ 48,6 48,21 @@ class WorkerDesktop : public sys::Worker, public bsp::USBDeviceListener
    void rawDataReceived(void *dataPtr, uint32_t dataLen) override;
    bool getRawMode() const noexcept override;

    void setEndpointSecurity(EndpointSecurity security)
    {
        endpointSecurity = security;
    }

    void enableEndpointSecurity(bool enable)
    {
        endpointSecurityEnabled = enable;
    }

    bool isEndpointSecurityEnabled()
    {
        return endpointSecurityEnabled;
    }

  private:
    void uploadFileFailedResponse();



@@ 60,9 75,12 @@ class WorkerDesktop : public sys::Worker, public bsp::USBDeviceListener
    bool stateChangeWait();

    xQueueHandle receiveQueue;
    xQueueHandle irqQueue;
    FILE *fileDes                  = nullptr;
    uint32_t writeFileSizeExpected = 0;
    uint32_t writeFileDataWritten  = 0;
    std::filesystem::path filePath;
    std::atomic<bool> rawModeEnabled = false;
    bool endpointSecurityEnabled     = true;
    EndpointSecurity endpointSecurity;
};

M module-services/service-desktop/tests/test-contacts.cpp => module-services/service-desktop/tests/test-contacts.cpp +10 -3
@@ 138,11 138,17 @@ bool DBServiceAPI::AddSMS(sys::Service *serv, const SMSRecord &record, std::uniq
}

xQueueHandle parserFSM::MessageHandler::sendQueue;
parserFSM::MessageHandler::MessageHandler(const std::string &message, sys::Service *OwnerService)
    : OwnerServicePtr(OwnerService)

parserFSM::MessageHandler::MessageHandler(sys::Service *OwnerService, std::unique_ptr<EndpointFactory> endpointFactory)
    : OwnerServicePtr(OwnerService), endpointFactory(std::move(endpointFactory))
{}

void parserFSM::MessageHandler::parseMessage(const std::string &msg)
{}

void parserFSM::MessageHandler::processMessage()
{}

void parserFSM::MessageHandler::putToSendQueue(const std::string &msg)
{
    messageStrings.push_back(msg);


@@ 174,7 180,8 @@ TEST_CASE("Endpoint Contacts Test")
        REQUIRE(err.empty());

        parserFSM::PagedContext context(msgJson, 10);
        auto handler = EndpointFactory::create(context, nullptr);
        auto factory = std::make_unique<SecuredEndpointFactory>(EndpointSecurity::Allow);
        auto handler = factory->create(context, nullptr);
        handler->handle(context);
        auto pageSize = context.getPageSize();
        REQUIRE(10 == pageSize);

M module-services/service-desktop/tests/unittest.cpp => module-services/service-desktop/tests/unittest.cpp +37 -3
@@ 25,7 25,6 @@
#include <string>
#include <vector>


TEST_CASE("System Update Tests")
{
    UpdateMuditaOS updateOS(nullptr);


@@ 49,6 48,10 @@ TEST_CASE("Parser Test")
{
    StateMachine parser(nullptr);

    auto factory = std::make_unique<SecuredEndpointFactory>(EndpointSecurity::Allow);
    auto handler = std::make_unique<parserFSM::MessageHandler>(nullptr, std::move(factory));
    parser.setMessageHandler(std::move(handler));

    SECTION("Parse message with divided header and payload")
    {
        std::string testMessage("#00000");


@@ 275,7 278,8 @@ TEST_CASE("Endpoint Factory test")
        REQUIRE(err.empty());

        Context context(msgJson);
        auto handler = EndpointFactory::create(context, nullptr);
        auto factory = std::make_unique<EndpointFactory>();
        auto handler = factory->create(context, nullptr);
        REQUIRE(dynamic_cast<ContactsEndpoint *>(handler.get()));
    }



@@ 287,7 291,37 @@ TEST_CASE("Endpoint Factory test")
        REQUIRE(err.empty());

        Context context(msgJson);
        auto handler = EndpointFactory::create(context, nullptr);
        auto factory = std::make_unique<EndpointFactory>();
        auto handler = factory->create(context, nullptr);
        REQUIRE(handler == nullptr);
    }
}

TEST_CASE("Secured Endpoint Factory test")
{
    SECTION("Allowed endpoint")
    {
        auto testMessage = R"({"endpoint":7, "method":1, "uuid":12345, "body":{"test":"test"}})";
        std::string err;
        auto msgJson = json11::Json::parse(testMessage, err);
        REQUIRE(err.empty());

        Context context(msgJson);
        auto factory = std::make_unique<SecuredEndpointFactory>(EndpointSecurity::Allow);
        auto handler = factory->create(context, nullptr);
        REQUIRE(dynamic_cast<ContactsEndpoint *>(handler.get()));
    }

    SECTION("Secured endpoint")
    {
        auto testMessage = R"({"endpoint":25, "method":8, "uuid":"12345", "body":{"te":"test"}})";
        std::string err;
        auto msgJson = json11::Json::parse(testMessage, err);
        REQUIRE(err.empty());

        Context context(msgJson);
        auto factory = std::make_unique<SecuredEndpointFactory>(EndpointSecurity::Block);
        auto handler = factory->create(context, nullptr);
        REQUIRE(dynamic_cast<SecuredEndpoint *>(handler.get()));
    }
}

M source/MessageType.hpp => source/MessageType.hpp +7 -0
@@ 215,8 215,15 @@ enum class MessageType
    Restore,
    Factory,
    DeveloperModeRequest,
    PasscodeRequest,
    TransferTimer,

    USBConnected,
    USBDisconnected,

    ScreenPasscodeRequest,
    ScreenPasscodeUnlocked,

    // FOTA messages
    HttpRequest,
    HttpResponse,

M test/harness/harness.py => test/harness/harness.py +7 -1
@@ 1,4 1,4 @@
# Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
# Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
import time
from enum import Enum


@@ 41,6 41,12 @@ class Harness:
    def get_application_name(self):
        return self.connection.get_application_name()

    def unlock_usb(self):
        self.connection.usb_unlock()

    def lock_usb(self):
        self.connection.usb_lock()

    def unlock_phone(self):
        if self.connection.is_phone_locked():
            self.connection.send_key_code(key_codes["enter"])

M test/harness/interface/CDCSerial.py => test/harness/interface/CDCSerial.py +16 -0
@@ 130,6 130,22 @@ class CDCSerial:
        ret = self.write(self.__wrap_message(body))
        return ret["body"]["isLocked"]

    def usb_lock(self):
        body = {
            "usbSecurity": "usbLock"
        }

        ret = self.write(self.__wrap_message(body))
        return ret["status"]

    def usb_unlock(self):
        body = {
            "usbSecurity": "usbUnlock"
        }

        ret = self.write(self.__wrap_message(body))
        return ret["status"]

    @staticmethod
    def find_Pures() -> str:
        '''

M test/harness/interface/defs.py => test/harness/interface/defs.py +1 -0
@@ 28,6 28,7 @@ status = {
    "OK": 200,
    "Accepted": 202,
    "BadRequest": 400,
    "Forbidden": 403,
    "NotAcceptable": 406,
    "InternalServerError": 500,
}

M test/pytest/conftest.py => test/pytest/conftest.py +7 -1
@@ 112,7 112,6 @@ def harness(request):
    else:
        return harness


@pytest.fixture(scope='session')
def harnesses():
    '''


@@ 130,6 129,13 @@ def phone_unlocked(harness):
    harness.unlock_phone()
    assert harness.is_phone_unlocked

@pytest.fixture(scope='session')
def usb_unlocked(harness):
    harness.unlock_usb()

@pytest.fixture(scope='session')
def usb_locked(harness):
    harness.lock_usb()

@pytest.fixture(scope='session')
def phones_unlocked(harnesses):

M test/pytest/service-desktop/test_backup.py => test/pytest/service-desktop/test_backup.py +1 -0
@@ 5,6 5,7 @@ from harness.interface.defs import status


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_backup(harness):
    body = {"backupReady": True}
    ret = harness.endpoint_request("backup", "get", body)

M test/pytest/service-desktop/test_battery_file.py => test/pytest/service-desktop/test_battery_file.py +1 -0
@@ 5,6 5,7 @@ from harness.interface.defs import status

@pytest.mark.rt1051
@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_battery_file(harness):
    body = {"command" : "checkFile" , "fileName" : "/sys/user/batteryFuelGaugeConfig.cfg"}
    ret = harness.endpoint_request("filesystemUpload", "post", body)

M test/pytest/service-desktop/test_bluetooth.py => test/pytest/service-desktop/test_bluetooth.py +2 -0
@@ 9,6 9,7 @@ import time

@pytest.mark.rt1051
@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_bluetooth_on_off(harness):
    body = {"state": True}
    ret = harness.endpoint_request("bluetooth", "get", body)


@@ 38,6 39,7 @@ def test_bluetooth_on_off(harness):

@pytest.mark.rt1051
@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_bluetooth_scan(harness):
    body = {"state": True}
    ret = harness.endpoint_request("bluetooth", "get", body)

M test/pytest/service-desktop/test_calendar.py => test/pytest/service-desktop/test_calendar.py +1 -0
@@ 6,6 6,7 @@ import copy

@pytest.mark.skip("not working on CI")
@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_calendar(harness):
    # add events
    add_body = {

M test/pytest/service-desktop/test_calllog.py => test/pytest/service-desktop/test_calllog.py +1 -0
@@ 5,6 5,7 @@ from harness.interface.defs import status


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_calllog(harness):
    # checking call log count
    body = {"count": True}

A test/pytest/service-desktop/test_connection_security.py => test/pytest/service-desktop/test_connection_security.py +40 -0
@@ 0,0 1,40 @@
# Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
import pytest
import time
from harness.interface.defs import status
from harness import utils, log

@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_locked")
def test_secured_endpoint(harness):
    body = {}

    ret = harness.endpoint_request("deviceInfo", "get", body)
    assert ret["status"] == status["Forbidden"]

    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["Forbidden"]

    ret = harness.endpoint_request("calllog", "get", body)
    assert ret["status"] == status["Forbidden"]

    ret = harness.endpoint_request("backup", "get", body)
    assert ret["status"] == status["Forbidden"]

    ret = harness.endpoint_request("contacts", "get", body)
    assert ret["status"] == status["Forbidden"]

    harness.unlock_usb()

    ret = harness.endpoint_request("deviceInfo", "get", body)
    assert ret["status"] == status["OK"]

    ret = harness.endpoint_request("calllog", "get", body)
    assert ret["status"] == status["OK"]

    ret = harness.endpoint_request("backup", "get", body)
    assert ret["status"] == status["OK"]

    ret = harness.endpoint_request("contacts", "get", body)
    assert ret["status"] == status["OK"]
\ No newline at end of file

M test/pytest/service-desktop/test_contacts.py => test/pytest/service-desktop/test_contacts.py +1 -0
@@ 5,6 5,7 @@ from harness.interface.defs import status


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_contacts(harness):
    # getting the contacts count
    body = {"limit": True}

M test/pytest/service-desktop/test_device_info.py => test/pytest/service-desktop/test_device_info.py +1 -0
@@ 4,6 4,7 @@ import pytest
from harness.interface.defs import status

@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_device_info(harness):
    body = {}
    ret = harness.endpoint_request("deviceInfo", "get", body)

M test/pytest/service-desktop/test_factory_reset.py => test/pytest/service-desktop/test_factory_reset.py +1 -0
@@ 6,6 6,7 @@ from harness.interface.defs import status

@pytest.mark.service_desktop_test
@pytest.mark.skip(reason="This will make a factory reset")
@pytest.mark.usefixtures("usb_unlocked")
def test_factory_reset(harness):
    body = {"factoryRequest": True}
    ret = harness.endpoint_request("factory", "post", body)

M test/pytest/service-desktop/test_messages.py => test/pytest/service-desktop/test_messages.py +1 -0
@@ 6,6 6,7 @@ from harness.interface.defs import status


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_messages(harness):
    # getting the messages count
    body = {"category": "message", "count": True}

M test/pytest/service-desktop/test_templates.py => test/pytest/service-desktop/test_templates.py +1 -0
@@ 5,6 5,7 @@ from harness.interface.defs import status


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_templates(harness):
    # getting the templates count
    body = {"category": "template", "count": True}

M test/pytest/service-desktop/test_threads.py => test/pytest/service-desktop/test_threads.py +1 -0
@@ 5,6 5,7 @@ from harness.interface.defs import status


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_threads(harness):
    # getting all threads
    body = {"category": "thread"}

M test/pytest/service-desktop/test_update.py => test/pytest/service-desktop/test_update.py +1 -0
@@ 5,6 5,7 @@ from harness.interface.defs import status


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_update(harness):
    body = {}
    ret = harness.endpoint_request("update", "get", body)