Revision control
++ // 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
++ {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
++ {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.
++ */