// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
    \example quicksecureclient
    \title Quick Secure CoAP Client
    \examplecategory {Connectivity}
    \ingroup qtcoap-examples
    \brief Securing the CoAP client and using it with a Qt Quick user interface.

    \image quicksecureclient.png
           {Secure CoAP client with certificate configuration and response}

    \e {Quick Secure CoAP Client} demonstrates how to create a secure CoAP client
    and use it in a Qt Quick application.

    \note Qt CoAP does not provide a QML API in its current version. However, you can
    make the C++ classes of the module available to QML as it is shown in the example.

    \include examples-run.qdocinc

    To run the example application, you first need to set up a secure CoAP server.
    You can run the example with any secure CoAP server supporting one of the
    \e {pre-shared key (PSK)} or \e certificate authentication modes. For more
    information about setting up a secure CoAP server, see
    \l {Setting Up a Secure CoAP Server}.

    \section1 Exposing C++ Classes to QML

    In this example, you need to expose the \l QCoapClient class and the
    \l {QtCoap Namespace}{QtCoap} namespace to QML. To achieve this, create a
    custom wrapper class and use the special \l {Defining QML Types from C++}
    {registration macros}.

    Create the \c QmlCoapSecureClient class as a wrapper around \l QCoapClient.
    This class also holds the selected security mode and security configuration
    parameters. Use the \l Q_INVOKABLE macro to expose several methods to QML.
    Also use the \l QML_NAMED_ELEMENT macro to register the class in QML as
    \c {CoapSecureClient}.

    \snippet quicksecureclient/qmlcoapsecureclient.h coap_client

    After that, register the \l {QtCoap Namespace}{QtCoap} namespace, so that
    you can use the enums provided there:
    \snippet quicksecureclient/qmlcoapsecureclient.h coap_namespace

    \section1 Adjusting Build Files

    To make the custom types available from QML, update the build system files
    accordingly.

    \section2 CMake

    For a CMake-based build, add the following to the \c {CMakeLists.txt}:

    \quotefromfile quicksecureclient/CMakeLists.txt
    \skipto qt_add_qml_module
    \printuntil )

    \section2 qmake

    For a qmake build, modify the \c {quicksecureclient.pro} file in the
    following way:

    \quotefromfile quicksecureclient/quicksecureclient.pro
    \skipto CONFIG
    \printuntil QML_IMPORT_MAJOR_VERSION
    \dots
    \skipto qml_resources.files
    \printuntil RESOURCES

    \section1 Using New QML Types

    Now, when the C++ classes are properly exposed to QML, you can use the new
    types.

    \section2 Creating the Client

    \c CoapSecureClient is instantiated from the \c {Main.qml} file. It handles
    the \c {QmlCoapSecureClient::finished()} signal and updates the UI
    accordingly:

    \snippet quicksecureclient/Main.qml client

    The instance of \l QCoapClient is created when the user selects or changes the
    security mode in the UI. The \c {QmlCoapSecureClient::setSecurityMode()} method
    is invoked from the QML code,  when one of the security modes is selected:

    \snippet quicksecureclient/Main.qml security_modes

    On the C++ side, this method creates a \l QCoapClient and connects to its
    \l {QCoapClient::}{finished()} and \l {QCoapClient::}{error()} signals. The
    class handles both signals internally, and forwards them to the new
    \c finished() signal.

    \snippet quicksecureclient/qmlcoapsecureclient.cpp set_security_mode

    \section2 Sending a Request

    Click the \uicontrol {Send Request} button to set the security configuration
    based on the selected security mode and send a \c GET request:

    \snippet quicksecureclient/Main.qml send_request

    There are two overloads for the \c setSecurityConfiguration method.

    The overload for the PSK mode simply sets the client identity and the
    pre-shared key:

    \snippet quicksecureclient/qmlcoapsecureclient.cpp set_configuration_psk

    And the overload for X.509 certificates reads the certificate files and
    the private key and sets the security configuration:

    \snippet quicksecureclient/qmlcoapsecureclient.cpp set_configuration_cert

    After setting the security configuration, the \c sendGetRequest method sets the
    request URL and sends a \c GET request:

    \snippet quicksecureclient/qmlcoapsecureclient.cpp send_get_request

    When sending the first request, a handshake with the CoAP server is performed.
    After the handshake is successfully done, all the subsequent messages are encrypted,
    and changing the security configuration after a successful handshake won't have any
    effect. If you want to change it, or change the host, you need to disconnect first.

    \snippet quicksecureclient/qmlcoapsecureclient.cpp disconnect

    This will abort the handshake and close the open sockets.

    For the authentication using X.509 certificates, the certificate files need
    to be specified. The \c FilePicker component is used for this purpose. It
    combines a text field and a button for opening a file dialog when the button
    is pressed:

    \snippet quicksecureclient/FilePicker.qml filepicker

    \c FilePicker is instantiated several times in the \c Main.qml file for
    creating input fields for certificates and the private key:

    \snippet quicksecureclient/Main.qml certificate_dialogs

    \section1 Setting Up a Secure CoAP Server

    To run this example, you need to have a secure CoAP server supporting either PSK
    or Certificate modes (or both). You have the following options:

    \list
        \li Manually build and run a secure CoAP server using, for example,
        \l {https://github.com/obgm/libcoap} {libcoap},
        \l {https://github.com/eclipse/californium} {Californium},
        \l {https://github.com/keith-cullen/FreeCoAP} {FreeCoAP},
        or any other CoAP library which supports DTLS.
        \li Use the ready Docker images available at Docker Hub, which build and run
        the secure CoAP servers suitable for our example. The steps required for using
        the docker-based CoAP servers are described below.
    \endlist

   \section2 Setting Up a Server For PSK Mode

    The following command pulls the docker container for a secure CoAP server based on
    \l {https://github.com/eclipse/californium/tree/master/demo-apps/cf-plugtest-server}
    {Californium plugtest} (which is not secure by default) from the Docker Hub and
    starts it:

    \badcode
    docker run --name coap-test-server -d --rm -p 5683:5683/udp -p 5684:5684/udp tqtc/coap-californium-test-server:3.8.0
    \endcode

    The CoAP test server will be reachable on ports \e 5683 (non-secure) and
    \e 5684 (secure). For instructions on retrieving the IP address see
    \l {Getting The IP Address}.

    To run the example with this server, you need to set the pre-shared key to
    \c secretPSK and the identity to \c Client_identity.

    \section2 Setting Up a Server For Certificate Mode

    The docker image of the secure server using authentication with X.509 certificates
    is based on the
    \l {https://github.com/keith-cullen/FreeCoAP/tree/master/sample/time_server}
    {time server} example from the FreeCoAP library. The following command pulls
    the container from Docker Hub and starts it:

    \badcode
    docker run --name coap-time-server -d --rm -p 5684:5684/udp tqtc/coap-secure-time-server:freecoap
    \endcode

    For instructions on retrieving the IP address see \l {Getting The IP Address}.
    The CoAP test server will be reachable by the retrieved IP address on port
    \e 5684 and resource path \c /time.

    To run the example with this server, you need to specify the certificate files
    required by the server. They are located in the docker container, under
    \c {/root/certs} directory. To copy them to a local directory, use the following
    command:

    \badcode
    docker cp <container_id>:/root/certs <local_directory_path>
    \endcode

    For example:

    \badcode
    $ docker cp 5e46502df88f:/root/certs ~/
    \endcode

    The instructions for getting the container ID are described below.

    \section2 Getting The IP Address

    To find out the IP address of a docker container, first retrieve the container ID
    by running the \c {docker ps} command, which will output something like:

    \badcode
    $ docker ps
    CONTAINER ID        IMAGE
    5e46502df88f        tqtc/coap-californium-test-server:3.8.0
    \endcode

    Then you can obtain the IP address with the following command:

    \badcode
    docker inspect <container_id> | grep IPAddress
    \endcode

    For example:

    \badcode
    $ docker inspect 5e46502df88f | grep IPAddress
    ...
    "IPAddress": "172.17.0.2",
    ...
    \endcode

    \section2 Terminating a Docker Container

    To terminate a docker container after usage, use the following command:

    \badcode
    docker stop <container_id>
    \endcode

    The \c {<container_id>} here is the same as retrieved by the \c {docker ps}
    command.
*/
