# AppWebsocket

The appwebsocket library contains a class AppWebsocket, which can be used as base class for a session object allocated for incoming websocket connections. This class handles the authentication protocol using the myPBX authentication. It relates to the innovaphone.appwebsocket.js library on the client side. There are member functions for sending and receiving messages.

### Protocol

JSON messages are used on this interface. There are some common properties, which are defined by the this library already, which is documented as AppWebsocket

### APIs

The library uses the mechanism defined by json_api.h to plug-in code to implement a specific API, which is addressed by the "api" property. Any App may use or provide APIs. These are documented in the context of these Apps. There are also libraries using this API mechanism (e.g. Replication).

## File information

File | common/lib/appwebsocket.h
Classes | AppWebsocket
Examples | Publishing app information Publishing service information Determining the base URL of an app instance

# Classes

## AppWebsocket

        class AppWebsocket : public UWebsocket, public IJsonApiConnection {

        ...

        public:

        AppWebsocket(IWebserverPlugin * plugin, class IInstanceLog * const log, class JsonApiContext * jsonApiContext = 0);
        ~AppWebsocket();

        virtual char * AppWebsocketPassword() { return 0; };
        virtual char * AppWebsocketPassword(const char * domain) { return NULL; };
        virtual const char * AppWebsocketInstanceDomain() { return NULL; };
        virtual void AppWebsocketMessage(class json_io & msg, word base, const char * mt, const char * src) = 0;
        virtual void AppWebsocketBinaryMessage(void * buffer, int len) { };
        virtual void AppWebsocketAppInfo(const char * app, class json_io & msg, word base) { }
        virtual void AppWebsocketServiceInfo(const char * app, class json_io & msg, word base) { }
        virtual const char * AppWebsocketDeviceAppType(const char * app) { return 0; }
        virtual void AppWebsocketLogin(class json_io & msg, word info) { };
        virtual bool AppWebsocketConnectComplete(class json_io & msg, word info) { return true; }
        virtual void AppWebsocketClosed() = 0;
        virtual bool AppWebsocketApiPermission(const char * api) { return true; }
        virtual void AppWebsocketSendResult() = 0;
        virtual void AppWebsocketCheckLogin(const char * src, const char * app, const char * domain, const char * challenge, const char * digest) { AppWebsocketCheckLoginComplete(src, app, domain, challenge, digest, AppWebsocketPassword()); };

        bool AppWebsocketLoginComplete(const char * password, char * key = 0, unsigned keyLen = 0);
        void AppWebsocketCheckLoginComplete(const char * src, const char * app, const char * domain, const char * challenge, const char * digest, const char * password);
        void AppWebsocketMessageComplete();
        void AppWebsocketMessageSend(class json_io & msg, char * buffer);
        void AppWebsocketMessageSendText(const char * buffer);
        void AppWebsocketMessageSendBinary(char * buffer, int len);
        void AppWebsocketClose();
        bool AppWebsocketCheckPassword(const char* password);

        void AppWebsocketEncrypt(const char * seed, const char * data, char * out, size_t outLen);
        void AppWebsocketDecrypt(const char * seed, const char * data, char * out, size_t outLen);
        void AppWebsocketHash(const char * seed, const char * data, char * out, size_t outLen);

        bool AppWebsocketIsEncryptedConnection();
        const char * AppWebsocketRemoteAddr();
        const char * AppWebsocketXForwaredFor();

        void RegisterJsonApi(class JsonApi * api, bool uniqueSrc = false) override;
        void UnRegisterJsonApi(class JsonApi * api) override;
        void JsonApiMessage(class json_io & msg, char * buffer, class JsonApi * response = 0) override;
        void JsonApiMessageText(const char * buffer, class JsonApi * response = 0) override;
        void JsonApiMessageComplete() override;
        bool JsonApiPermission(const char * api) override;

        char * domain;
        char * sip;
        char * guid;
        char * dn;
        char * app;
        char key[65];
        bool unlicensed;
        bool pbxConnection;
        bool pbxManagerConnection;

        };

Base class for incoming AppWebsocket sessions. It provides public functions which may be called by the application and virtual function, which may be overridden for the signaling of events on the protocol.

virtual AppWebsocket
  Contructor used to initialize the class.

  #### Parameters

  IWebserverPlugin * plugin | The IWebserverPlugin object passed in the WebserverWebsocketListenResult function.
  class IInstanceLog * const log | The log is used to log dependent of the log flag LOG_APP_WEBSOCKET.
  class JsonApiContext * jsonApiContext | Optional parameter, needed if other libraries, based on the JsonApi mechanism are used (e.g. config.h).

virtual AppWebsocketPassword (overloaded)
  Called by the library to read the shared secret, which is part of the App instance configuration.

  #### Return value

  The app instance password. If null is returned, the function AppWebsocketLogin is called to start assynchronous athentication.
virtual AppWebsocketPassword (overloaded)
  Called by the library to read another domain dependent shared secret, if the first shared secret failed.

  #### Parameters

  const char * domain | The domain name.

  #### Return value

  The domain password, if defined. If null is returned, the function AppWebsocketLogin is called to start assynchronous athentication.
virtual AppWebsocketInstanceDomain
  Called by the library to read the App Instance domain. It is sent within the AppLoginResult message as property "domain".

  #### Return value

  The domain name of the instance.
virtual AppWebsocketConnectComplete
  Will be called after the connection / authentication process had been completed and with that the AppWebsocket connection had been established. The default implementation is just an empty function, which returns true

  #### Parameters

  class json_io & msg | The message as JSON data structure.
  word info | Indicates the location of the info structure inside the message. The info structure contains additional user, app and licensing information. For Details see the protocol definition: AppWebsocket.

  #### Return value

  The application should return true to indicate, that it is ready to receive messages. If false is returned, a call to AppWebsocketMessageComplete() is needed to receive messages.
virtual AppWebsocketMessage
  Called by the library on received messages. The message is json decoded.

  #### Parameters

  class json_io & msg | The message as JSON data structure.
  word base | indicates the location of message inside the JSON structure
  const char * src | The "src" member of the message. This should be sent back with any response. It is used on the Javascript side to route the message to the object, which sent the request.

virtual AppWebsocketBinaryMessage
  Called by the library on received binary messages.

  #### Parameters

  void * buffer | The message.
  int len | The length of the message.
  const char * src | The "src" member of the message. This should be sent back with any response. It is used on the Javascript side to route the message to the object, which sent the request.

virtual AppWebsocketMessageComplete
  Function to be called to acknowledge the last message. Unless this function is called no further message is received.
virtual AppWebsocketMessageSend
  Function which can be called to send a message. buffer should be a buffer big enough to hold the complete message. It is used only during the call to this function.

  #### Parameters

  class json_io & msg | The message as JSON data structure.
  char * buffer | A buffer that shall be used for encoding the message. Must be big enough to contain the whole message.

virtual AppWebsocketSendResult
  Called by the library when the message is sent. The App should not send further messages unless this call is received, if the App wants to have flow control for bulk data. If flow control on application level is done, this function needs not to be implemented.
AppWebsocketClose
  Can be called to request closing of the websocket connection
AppWebsocketCheckPassword
  This function can be used to check if the provided password is valid for the current AppWebsocket session.

  #### Parameters

  const char * password | The password to check.

  #### Return Value

  Returns `true` if the password is correct, otherwise `false`.
virtual AppWebsocketClosed
  Called when the websocket connection is closed. It can be used to delete the App session (e.g. delete this).
virtual AppWebsocketAppInfo
  Called by the library to get information of the specified app. This includes for example if the app is hidden and which client APIs are provided by the app. The application is supposed to encode a JSON structure containing the information.

  #### Parameters

  const char * app | The name of the app for which the information is requested.
  class json_io & msg | A JSON structure to put the information.
  word base | The position inside the JSON structure where to put the information.

  #### Information that can be published in the JSON

  hidden | `true` if the app is an API provider without a UI. Hidden apps are run in the background without displaying them to the user.
  presence | `true` if the app instance provides presence for badge counts on the AppWebsocket connection using the PbxSignal API.
  apis | An object that should contain an object for each client API that is provided by the app. Please see the Example.

virtual AppWebsocketServiceInfo
  Called by the library to get information about the websocket services of a certain app instance. The application is supposed to encode a JSON structure containing the information.

  #### Parameters

  const char * app | The name of the app for which the information is requested.
  class json_io & msg | A JSON structure to put the information.
  word base | The position inside the JSON structure where to put the information.

virtual AppWebsocketDeviceAppType
  Called by the library to get information about the device app type. This happens when an AppInfo message is received.

  #### Parameters

  const char * app | The name of the app for which the information is requested.

  #### Return Value

  A string, which is sent as "deviceapp" property in the AppInfoResult message.
virtual AppWebsocketLogin
  Called by the library if null is returned on AppWebsocketPassword, so that the Login can be handled assynchronously in the application

  #### Parameters

  class json_io & msg | Json data which contains the AppLogin message
  word info | Handle of the info object inside the AppLogin message.

  #### Return Value

  A string, which is sent as "deviceapp" property in the AppInfoResult message.
virtual AppWebsocketApiPermission
  Called by the library when the function JsonApiPermission is called by an JsonApi implementation, so that the application can check if the use of the Api is allowed in the context of this session.

  #### Parameters

  const char * api | The Api id.

  #### Return Value

  Return true to allow the use of the Api.
virtual AppWebsocketCheckLogin
  Called by the library when the message AppCheckLogin is received. This can be used to check if a login is valid. The PBX Manager uses this function to verify if the passwords stored in App objects are valid. The default implementation calls AppWebsocketCheckLoginComplete with AppWebsocketPassword, so that this check works in case the AppWebsocketPassword function is used for the password.

  #### Parameters

  const char * src | The src property as received
  const char * app | The app propery as received
  const char * domain | The domain name as received
  const char * challenge | The challenge property as received
  const char * digest | The digest propery as received

virtual AppWebsocketLoginComplete
  Called by the application to complete a login process started with the AppWebsocketLogin call

  #### Parameters

  const char * password | The password used to check the login.
  char * key | Optional buffer to copy the session key into.
  unsigned keyLen | Length of the key buffer.

virtual AppWebsocketCheckLoginComplete
  Called by the application to complete a check login process started with the AppWebsocketCheckLogin call

  #### Parameters

  const char * src | The src as received in AppWebsocketCheckLogin
  const char * app | The app as received in AppWebsocketCheckLogin
  const char * domain | The domain name as received in AppWebsocketCheckLogin
  const char * challenge | The challenge as received in AppWebsocketCheckLogin
  const char * digest | The digest as received in AppWebsocketCheckLogin
  const char * password | The password to be used for the check

virtual AppWebsocketMessageSendText
  Can be used to send a plain text message

  #### Parameters

  const char * buffer | Zero terminated string which is sent

virtual AppWebsocketMessageSendBinary
  Can be used to send a binary message

  #### Parameters

  char * buffer | Buffer containing the binary message.
  int len | Length of the message in bytes.

AppWebsocketEncrypt
  Can be used to encrypt a text send on the AppWebsocket connection, using the session key

  #### Parameters

  const char * seed | Seed, which can be used so that the result of the encryption is different even if the data is the same.
  const char * data | Buffer containing the data to be encrypted as zero terminated string
  char * out | Buffer for the encrypted output as hex string.
  size_t outLen | Length of the buffer for the output. Must be 2 times the length of the data string.

AppWebsocketDecrypt
  Can be used to dencrypt a text send on the AppWebsocket connection, using the session key

  #### Parameters

  const char * seed | Seed, which can be used so that the result of the encryption is different even if the data is the same.
  const char * data | Buffer containing the hex string of encryped data
  char * out | Buffer for the decrypted output
  size_t outLen | Length of the buffer for the output. Must be half the length of the data string.

AppWebsocketHash
  Calculate a SHA256 hash using the session key

  #### Parameters

  const char * seed | Seed, which can be used so that the result of the encryption is different even if the data is the same.
  const char * data | Buffer containing a zero terminated string over which the hash shall be calculated
  char * out | Buffer for the hash
  size_t outLen | Length of the buffer for the output. Must be 64 bytes, 2* HASH_SIZE_SHA256

AppWebsocketIsEncryptedConnection
  Returns true if a TLS connection is used
AppWebsocketRemoteAddr
  Returns the remote address of the underlying socket.
AppWebsocketXForwaredFor
  Returns the X-Forwarded-For header of the initial HTTP GET request for the websocket connection.
RegisterJsonApi
  Used by an Api implementation to register the Api to the session. Needed to receive messages with the matching "api" property. This is usually called when the Api implementation is called with JsonApiRequested, when a new api value is received

  #### Parameters

  class JsonApi * api | The class for the Api implementation
  bool uniqueSrc | This can be set to true, if the library is not used to provide an Api, but to access a remote Api. It should not be set, when providing an Api. A unique src is generated, which is available as member "src" of JsonApi. The src can be used when sending Requests, it is checked for responses to route these to the correct JsonApi.

UnRegisterJsonApi
  Used by an Api implementation to unregister the Api from the session.

  #### Parameters

  class JsonApi * api | The class for the Api implementation

JsonApiMessage
  Used by a JsonApi implementation to send a message

  #### Parameters

  class json_io & msg | The message to be sent
  char * buffer | A buffer big enough to contain the message
  class JsonApi * response | Optional argument to request a JsonApiResponseSent() callback to the JsonApi. It can be used to trigger the next response. For each JsonApiMessage with the response argument, there will be a JsonApiResponseSent() callback.

JsonApiMessageComplete
  Used by a JsonApi implementation to acknowledge a received message so that the next message is received
JsonApiPermission
  Used by a JsonApi implementation to check if the use of the Api is allowed for this session

  #### Parameters

  const char * api | The name of the api.

  #### Return value

  Return true to allow the use of the Api.
domain
  The domain of the logged in user, if available.
  This member variable is set by the library before the AppWebsocketConnectComplete callback is invoked.
sip
  The SIP URI of the logged in user, if available.
  This member variable is set by the library before the AppWebsocketConnectComplete callback is invoked.
dn
  The display name of the logged in user, if available.
  This member variable is set by the library before the AppWebsocketConnectComplete callback is invoked.
app
  The HTML file name of the app. Can be used to determine which app created this current connection.
  This member variable is set by the library before the AppWebsocketConnectComplete callback is invoked.
key
  A shared secret between between app and app service that is valid for the connection.
  This member variable is set by the library before the AppWebsocketConnectComplete callback is invoked.
unlicensed
  True, if the user does not have a valid license for the app specified in the app variable.
  This member variable is set by the library before the AppWebsocketConnectComplete callback is invoked.
pbxConnection
  True, if the connection was established by an app object inside the PBX.
  The library determines PBX connections using the following rules:
  - Login.sip is equal to Login.info.appobj (Login by the app object itself)
  This member variable is set by the library before the AppWebsocketConnectComplete callback is invoked.
pbxManagerConnection
  True, if the connection was established by a settings plugin.
  The library determines connections from a settings plugin using the following rules:
  - Login.info.appobj is undefined.
  - app is "-"
  This member variable is set by the library before the AppWebsocketConnectComplete callback is invoked.

# Code Examples

## Publishing app information

    void MySession::AppWebsocketAppInfo(const char * app, class json_io & msg, word base)
    {
        if (!strcmp(app, "my-searchprovider")) {
            // general app info
            msg.add_bool(base, "hidden", true); // app is hidden
            msg.add_bool(base, "presence", true); // app provides presence (badge counts)

            // apis
            word apis = msg.add_object(base, "apis");
            word search = msg.add_object(apis, "com.innovaphone.search");
            word info = msg.add_object(search, "info");
            msg.add_string(info, "someattr", "somevalue");
        }
    }

## Publishing service information

    void MySession::AppWebsocketServiceInfo(const char * app, class json_io & msg, word base)
    {
        if (!strcmp(app, "my-channels-service")) {
            word apis = msg.add_object(base, "apis");
            msg.add_object(apis, "com.innovaphone.channels");
        }
    }

## Determining the base URL of the app instance

Sometimes an app service needs to know its own base URL. This is necessary, for instance, when the service wants to create permanent HTTP links to itself.
To do this, the service can use the incoming AppWebsocket connections from PBXes. These connections transmit the URL that's configured in the app object as part of the login information.

    bool MySession::AppWebsocketConnectComplete(class json_io & msg, word info)
    {
        if (pbxConnection) {
            SaveUrl(msg.get_string(info, "appurl"));
        }
        return true
    }

    void MySession::SaveUrl(const char * url)
    {
        if (url) {
            //Copy the new URL
            free(baseUrl);
            baseUrl = _strdup(url);

            // Truncate at the last trailing slash.
            //    e.g. https://apps.example.com/domain/manufacturer-app/manufacturer-app.htm
            //      => https://apps.example.com/domain/manufacturer-app/
            char * slash = strrchr(baseUrl, '/');
            if (slash && *(slash + 1)) *(slash + 1) = 0;
        }
    }