Commit 56f8643e authored by Matthieu Tanon's avatar Matthieu Tanon

Feature/encrypted chatrooms

parent 8ae88981
......@@ -127,6 +127,13 @@ static char* _get_identity(const LinphoneAccountCreator *creator) {
return identity;
}
static inline void resetField (char **field) {
if (*field) {
bctbx_free(*field);
*field = nullptr;
}
}
LinphoneProxyConfig * linphone_account_creator_create_proxy_config(const LinphoneAccountCreator *creator) {
LinphoneAuthInfo *info;
LinphoneProxyConfig *cfg = linphone_core_create_proxy_config(creator->core);
......@@ -168,6 +175,7 @@ LinphoneProxyConfig * linphone_account_creator_create_proxy_config(const Linphon
}
linphone_core_remove_auth_info(creator->core, info);
linphone_auth_info_unref(info);
return NULL;
}
......@@ -305,7 +313,7 @@ static void _linphone_account_creator_destroy(LinphoneAccountCreator *creator) {
linphone_account_creator_service_get_destructor_cb(creator->service)(creator);
linphone_account_creator_service_unref(creator->service);
}
linphone_account_creator_cbs_unref(creator->cbs);
if (creator->proxy_cfg) {
linphone_proxy_config_unref(creator->proxy_cfg);
......@@ -348,28 +356,20 @@ LinphoneAccountCreator * linphone_account_creator_new(LinphoneCore *core, const
return _linphone_account_creator_new(core, xmlrpc_url);
}
#define _reset_field(field) \
if (field) { \
ms_free(field); \
field = NULL; \
}
void linphone_account_creator_reset(LinphoneAccountCreator *creator) {
_reset_field(creator->username);
_reset_field(creator->display_name);
_reset_field(creator->password);
_reset_field(creator->ha1);
_reset_field(creator->phone_number);
_reset_field(creator->phone_country_code);
_reset_field(creator->email);
_reset_field(creator->language);
_reset_field(creator->activation_code);
_reset_field(creator->domain);
_reset_field(creator->route);
resetField(&creator->username);
resetField(&creator->display_name);
resetField(&creator->password);
resetField(&creator->ha1);
resetField(&creator->phone_number);
resetField(&creator->phone_country_code);
resetField(&creator->email);
resetField(&creator->language);
resetField(&creator->activation_code);
resetField(&creator->domain);
resetField(&creator->route);
}
#undef _reset_field
LinphoneAccountCreator * linphone_core_create_account_creator(LinphoneCore *core, const char *xmlrpc_url) {
return _linphone_account_creator_new(core, xmlrpc_url);
}
......@@ -407,7 +407,7 @@ LinphoneAccountCreatorUsernameStatus linphone_account_creator_set_username(Linph
bool_t use_phone_number = !!lp_config_get_int(creator->core->config, "assistant", "use_phone_number", 0);
const char* regex = lp_config_get_string(creator->core->config, "assistant", "username_regex", 0);
if (!username) {
creator->username = NULL;
resetField(&creator->username);
return LinphoneAccountCreatorUsernameStatusOk;
} else if (min_length > 0 && strlen(username) < (size_t)min_length) {
return LinphoneAccountCreatorUsernameStatusTooShort;
......@@ -482,7 +482,7 @@ LinphoneAccountCreatorPasswordStatus linphone_account_creator_set_password(Linph
int min_length = lp_config_get_int(creator->core->config, "assistant", "password_min_length", -1);
int max_length = lp_config_get_int(creator->core->config, "assistant", "password_max_length", -1);
if (!password) {
creator->password = NULL;
resetField(&creator->password);
return LinphoneAccountCreatorPasswordStatusTooShort;
}
if (min_length > 0 && strlen(password) < (size_t)min_length) {
......@@ -1147,7 +1147,7 @@ LinphoneAccountCreatorStatus linphone_account_creator_link_phone_number_with_acc
}
return LinphoneAccountCreatorStatusMissingArguments;
}
if (creator->xmlrpc_session) {
ms_debug("Account creator: link_phone_number_with_account (phone number=%s, username=%s, domain=%s, language=%s)",
creator->phone_number,
......
......@@ -93,11 +93,8 @@ static void call_received(SalCallOp *h) {
linphone_address_unref(toAddr);
linphone_address_unref(fromAddr);
if (sal_address_has_param(h->getRemoteContactAddress(), "text")) {
bool oneToOneChatRoom = false;
const char *oneToOneChatRoomStr = sal_custom_header_find(h->getRecvCustomHeaders(), "One-To-One-Chat-Room");
if (oneToOneChatRoomStr && (strcmp(oneToOneChatRoomStr, "true") == 0))
oneToOneChatRoom = true;
if (oneToOneChatRoom) {
if (oneToOneChatRoomStr && (strcmp(oneToOneChatRoomStr, "true") == 0)) {
bool_t oneToOneChatRoomEnabled = linphone_config_get_bool(linphone_core_get_config(lc), "misc", "enable_one_to_one_chat_room", TRUE);
if (!oneToOneChatRoomEnabled) {
h->decline(SalReasonNotAcceptable);
......@@ -111,7 +108,11 @@ static void call_received(SalCallOp *h) {
h->release();
return;
}
IdentityAddress confAddr = L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb->findOneToOneConferenceChatRoomAddress(from, identAddresses.front());
bool encrypted = false;
const char *endToEndEncryptedStr = sal_custom_header_find(h->getRecvCustomHeaders(), "End-To-End-Encrypted");
if (endToEndEncryptedStr && (strcmp(endToEndEncryptedStr, "true") == 0))
encrypted = true;
IdentityAddress confAddr = L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb->findOneToOneConferenceChatRoomAddress(from, identAddresses.front(), encrypted);
if (confAddr.isValid()) {
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ConferenceId(confAddr, confAddr));
L_GET_PRIVATE(static_pointer_cast<ServerGroupChatRoom>(chatRoom))->confirmRecreation(h);
......@@ -145,10 +146,16 @@ static void call_received(SalCallOp *h) {
chatRoom->deleteFromDb();
chatRoom.reset();
}
if (!chatRoom)
if (!chatRoom) {
bool encrypted = false;
const char *endToEndEncryptedStr = sal_custom_header_find(h->getRecvCustomHeaders(), "End-To-End-Encrypted");
if (endToEndEncryptedStr && (strcmp(endToEndEncryptedStr, "true") == 0)) {
encrypted = true;
}
chatRoom = L_GET_PRIVATE_FROM_C_OBJECT(lc)->createClientGroupChatRoom(
h->getSubject(), h->getRemoteContact(), h->getRemoteBody(), false
h->getSubject(), h->getRemoteContact(), h->getRemoteBody(), false, encrypted
);
}
const char *oneToOneChatRoomStr = sal_custom_header_find(h->getRecvCustomHeaders(), "One-To-One-Chat-Room");
if (oneToOneChatRoomStr && (strcmp(oneToOneChatRoomStr, "true") == 0))
......@@ -850,8 +857,10 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
ConferenceId(addr, IdentityAddress(op->getTo()))
);
if (!chatRoom)
chatRoom = L_GET_PRIVATE_FROM_C_OBJECT(lc)->createClientGroupChatRoom("", addr.asString(), Content(), false);
if (!chatRoom) {
bool encrypted = false; // TODO get encryption information from INVITE
chatRoom = L_GET_PRIVATE_FROM_C_OBJECT(lc)->createClientGroupChatRoom("", addr.asString(), Content(), false, encrypted);
}
chatRoom->join();
static_cast<SalReferOp *>(op)->reply(SalReasonNone);
return;
......
......@@ -99,6 +99,10 @@ LinphoneChatRoom *linphone_core_create_client_group_chat_room (LinphoneCore *lc,
return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->createClientGroupChatRoom(L_C_TO_STRING(subject), !!fallback));
}
LinphoneChatRoom *linphone_core_create_client_group_chat_room_2 (LinphoneCore *lc, const char *subject, bool_t fallback, bool_t encrypted) {
return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->createClientGroupChatRoom(L_C_TO_STRING(subject), !!fallback, !!encrypted));
}
LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc, LinphonePrivate::SalCallOp *op) {
return _linphone_server_group_chat_room_new(lc, op);
}
......@@ -129,8 +133,22 @@ LinphoneChatRoom *linphone_core_find_one_to_one_chat_room (
) {
return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findOneToOneChatRoom(
LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(local_addr)),
LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(participant_addr))
));
LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(participant_addr)),
false)
);
}
LinphoneChatRoom *linphone_core_find_one_to_one_chat_room_2 (
const LinphoneCore *lc,
const LinphoneAddress *local_addr,
const LinphoneAddress *participant_addr,
bool_t encrypted
) {
return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findOneToOneChatRoom(
LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(local_addr)),
LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(participant_addr)),
encrypted)
);
}
int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *sal_msg) {
......
......@@ -89,6 +89,7 @@ set(C_API_HEADER_FILES
c-event-log.h
c-magic-search.h
c-participant.h
c-participant-device.h
c-participant-imdn-state.h
c-search-result.h
c-types.h
......
......@@ -73,8 +73,9 @@ LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_create_acc
* Send a request to delete an account on server.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
* @donotwrap This is a security breach, exists for tests purposes only
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_delete_account(LinphoneAccountCreator *creator);
LinphoneAccountCreatorStatus linphone_account_creator_delete_account(LinphoneAccountCreator *creator);
/**
* Send a request to know if an account is activated on server.
......@@ -87,8 +88,9 @@ LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_account
* Send a request to get the account confirmation key on server.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
* @donotwrap This is a security breach, exists for tests purposes only
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_get_confirmation_key(LinphoneAccountCreator *creator);
LinphoneAccountCreatorStatus linphone_account_creator_get_confirmation_key(LinphoneAccountCreator *creator);
/**
* Send a request to activate an account on server.
......@@ -411,15 +413,17 @@ LINPHONE_PUBLIC void linphone_account_creator_cbs_set_create_account(LinphoneAcc
* Get the delete account request.
* @param[in] cbs LinphoneAccountCreatorCbs object.
* @return The current delete account request.
* @donotwrap This is a security breach, exists for tests purposes only
**/
LINPHONE_PUBLIC LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_delete_account(const LinphoneAccountCreatorCbs *cbs);
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_delete_account(const LinphoneAccountCreatorCbs *cbs);
/**
* Assign a user pointer to a LinphoneAccountCreatorCbs object.
* @param[in] cbs LinphoneAccountCreatorCbs object.
* @param[in] cb The delete account request to be used.
* @donotwrap This is a security breach, exists for tests purposes only
**/
LINPHONE_PUBLIC void linphone_account_creator_cbs_set_delete_account(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb);
void linphone_account_creator_cbs_set_delete_account(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb);
/**
* Get the is account exist request.
......@@ -439,15 +443,17 @@ LINPHONE_PUBLIC void linphone_account_creator_cbs_set_is_account_exist(LinphoneA
* Get the get confirmation key request.
* @param[in] cbs LinphoneAccountCreatorCbs object.
* @return The current is account exist request.
* @donotwrap This is a security breach, exists for tests purposes only
**/
LINPHONE_PUBLIC LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_get_confirmation_key(const LinphoneAccountCreatorCbs *cbs);
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_get_confirmation_key(const LinphoneAccountCreatorCbs *cbs);
/**
* Assign a user pointer to a LinphoneAccountCreatorCbs object.
* @param[in] cbs LinphoneAccountCreatorCbs object.
* @param[in] cb The get confirmation key request to be used.
* @donotwrap This is a security breach, exists for tests purposes only
**/
LINPHONE_PUBLIC void linphone_account_creator_cbs_set_get_confirmation_key(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb);
void linphone_account_creator_cbs_set_get_confirmation_key(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb);
/**
* Get the activate account request.
......
......@@ -37,6 +37,7 @@
#include "linphone/api/c-magic-search.h"
#include "linphone/api/c-participant-imdn-state.h"
#include "linphone/api/c-participant.h"
#include "linphone/api/c-participant-device.h"
#include "linphone/api/c-search-result.h"
#include "linphone/api/c-types.h"
......
/*
* c-participant-device.h
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_C_PARTICIPANT_DEVICE_H_
#define _L_C_PARTICIPANT_DEVICE_H_
#include "linphone/api/c-types.h"
// =============================================================================
#ifdef __cplusplus
extern "C" {
#endif // ifdef __cplusplus
/**
* @addtogroup misc
* @{
*/
/**
* Increment reference count of #LinphoneParticipantDevice object.
**/
LINPHONE_PUBLIC LinphoneParticipantDevice *linphone_participant_device_ref (LinphoneParticipantDevice *participant_device);
/**
* Decrement reference count of #LinphoneParticipantDevice object.
**/
LINPHONE_PUBLIC void linphone_participant_device_unref (LinphoneParticipantDevice *participant_device);
/**
* Retrieve the user pointer associated with the participant's device.
* @param[in] participant_device A #LinphoneParticipantDevice object
* @return The user pointer associated with the participant's device.
**/
LINPHONE_PUBLIC void * linphone_participant_device_get_user_data(const LinphoneParticipantDevice *participant_device);
/**
* Assign a user pointer to the participant's device.
* @param[in] participant_device A #LinphoneParticipantDevice object
* @param[in] ud The user pointer to associate with the participant's device
**/
LINPHONE_PUBLIC void linphone_participant_device_set_user_data(LinphoneParticipantDevice *participant_device, void *ud);
/**
* Get the address of a participant's device.
* @param[in] participant_device A #LinphoneParticipantDevice object
* @return The address of the participant's device
*/
LINPHONE_PUBLIC const LinphoneAddress * linphone_participant_device_get_address (const LinphoneParticipantDevice *participant_device);
/**
* Get the security level of a participant's device.
* @param[in] participant_device A #LinphoneParticipantDevice object
* @return The security level of the device
*/
LINPHONE_PUBLIC LinphoneChatRoomSecurityLevel linphone_participant_device_get_security_level (const LinphoneParticipantDevice *participant_device);
/**
* @}
*/
#ifdef __cplusplus
}
#endif // ifdef __cplusplus
#endif // ifndef _L_C_PARTICIPANT_DEVICE_H_
......@@ -78,6 +78,13 @@ LINPHONE_PUBLIC bool_t linphone_participant_is_admin (const LinphoneParticipant
*/
LINPHONE_PUBLIC LinphoneChatRoomSecurityLevel linphone_participant_get_security_level (const LinphoneParticipant *participant);
/**
* Gets the list of devices from a chat room's participant.
* @param[in] participant A #LinphoneParticipant object
* @return \bctbx_list{LinphoneParticipantDevice}
*/
LINPHONE_PUBLIC bctbx_list_t *linphone_participant_get_devices (const LinphoneParticipant *participant);
/**
* @}
*/
......
......@@ -175,6 +175,11 @@ typedef struct _LinphoneParticipant LinphoneParticipant;
*/
typedef struct _LinphoneParticipantImdnState LinphoneParticipantImdnState;
/**
* @ingroup misc
*/
typedef struct _LinphoneParticipantDevice LinphoneParticipantDevice;
/**
* The LinphoneSearchResult object represents a result of a search
* @ingroup misc
......
......@@ -5177,6 +5177,18 @@ LINPHONE_DEPRECATED LINPHONE_PUBLIC const char *linphone_core_get_chat_database_
*/
LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const char *subject, bool_t fallback);
/**
* Create a client-side group chat room. When calling this function the chat room is only created
* at the client-side and is empty. You need to call linphone_chat_room_add_participants() to
* create at the server side and add participants to it.
* @param[in] lc A #LinphoneCore object
* @param[in] subject The subject of the group chat room
* @param[in] fallback Boolean value telling whether we should plan on being able to fallback to a basic chat room if the client-side group chat room creation fails
* @param[in] encrypted Boolean value telling whether we should apply encryption or not on chat messages sent and received on this room.
* @return The newly created client-side group chat room.
*/
LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_create_client_group_chat_room_2 (LinphoneCore *lc, const char *subject, bool_t fallback, bool_t encrypted);
/**
* Get a basic chat room whose peer is the supplied address. If it does not exist yet, it will be created.
* No reference is transfered to the application. The #LinphoneCore keeps a reference on the chat room.
......@@ -5230,6 +5242,7 @@ LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_find_chat_room (
* @param local_addr a linphone address.
* @param participant_addr a linphone address.
* @return #LinphoneChatRoom where messaging can take place.
* @deprecated Use linphone_core_find_one_to_one_chat_room_2 instead
**/
LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_find_one_to_one_chat_room (
const LinphoneCore *lc,
......@@ -5237,6 +5250,22 @@ LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_find_one_to_one_chat_room (
const LinphoneAddress *participant_addr
);
/**
* Find a one to one chat room.
* No reference is transfered to the application. The #LinphoneCore keeps a reference on the chat room.
* @param lc the linphone core
* @param local_addr a linphone address.
* @param participant_addr a linphone address.
* @param encrypted whether to look for an encrypted chat room or not
* @return #LinphoneChatRoom where messaging can take place.
**/
LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_find_one_to_one_chat_room_2 (
const LinphoneCore *lc,
const LinphoneAddress *local_addr,
const LinphoneAddress *participant_addr,
bool_t encrypted
);
/**
* Removes a chatroom including all message history from the LinphoneCore.
* @param lc A #LinphoneCore object
......
......@@ -39,6 +39,7 @@
F(Conference /**< Use server (supports group chat) */, 1 << 2) \
F(Proxy /**< Special proxy chat room flag */, 1 << 3) \
F(Migratable /**< Chat room migratable from Basic to Conference */, 1 << 4) \
F(OneToOne /**< A communication between two participants (can be Basic or Conference) */, 1 << 5)
F(OneToOne /**< A communication between two participants (can be Basic or Conference) */, 1 << 5) \
F(Encrypted /**< Chat room is encrypted */, 1 << 6)
#endif // ifndef _L_CHAT_ROOM_ENUMS_H_
......@@ -250,6 +250,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
c-wrapper/api/c-event-log.cpp
c-wrapper/api/c-magic-search.cpp
c-wrapper/api/c-participant.cpp
c-wrapper/api/c-participant-device.cpp
c-wrapper/api/c-participant-imdn-state.cpp
c-wrapper/api/c-search-result.cpp
c-wrapper/internal/c-sal.cpp
......
/*
* c-participant-device.cpp
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/api/c-participant-device.h"
#include "address/address.h"
#include "c-wrapper/c-wrapper.h"
#include "conference/participant-device.h"
// =============================================================================
using namespace std;
L_DECLARE_C_OBJECT_IMPL(ParticipantDevice,
mutable LinphoneAddress *addressCache;
);
LinphoneParticipantDevice *linphone_participant_device_ref (LinphoneParticipantDevice *participant_device) {
belle_sip_object_ref(participant_device);
return participant_device;
}
void linphone_participant_device_unref (LinphoneParticipantDevice *participant_device) {
belle_sip_object_unref(participant_device);
}
void *linphone_participant_device_get_user_data(const LinphoneParticipantDevice *participant_device) {
return L_GET_USER_DATA_FROM_C_OBJECT(participant_device);
}
void linphone_participant_device_set_user_data(LinphoneParticipantDevice *participant_device, void *ud) {
L_SET_USER_DATA_FROM_C_OBJECT(participant_device, ud);
}
const LinphoneAddress *linphone_participant_device_get_address(const LinphoneParticipantDevice *participant_device) {
LinphonePrivate::Address addr(L_GET_CPP_PTR_FROM_C_OBJECT(participant_device)->getAddress());
if (participant_device->addressCache)
linphone_address_unref(participant_device->addressCache);
participant_device->addressCache = linphone_address_new(addr.asString().c_str());
return participant_device->addressCache;
}
LinphoneChatRoomSecurityLevel linphone_participant_device_get_security_level (const LinphoneParticipantDevice *participant_device) {
return (LinphoneChatRoomSecurityLevel)L_GET_CPP_PTR_FROM_C_OBJECT(participant_device)->getSecurityLevel();
}
\ No newline at end of file
......@@ -21,7 +21,8 @@
#include "address/address.h"
#include "c-wrapper/c-wrapper.h"
#include "conference/participant.h"
#include "conference/participant-p.h"
#include "conference/participant-device.h"
// =============================================================================
......@@ -62,4 +63,7 @@ bool_t linphone_participant_is_admin (const LinphoneParticipant *participant) {
LinphoneChatRoomSecurityLevel linphone_participant_get_security_level (const LinphoneParticipant *participant) {
return (LinphoneChatRoomSecurityLevel)L_GET_CPP_PTR_FROM_C_OBJECT(participant)->getSecurityLevel();
}
\ No newline at end of file
}
bctbx_list_t *linphone_participant_get_devices (const LinphoneParticipant *participant) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_PRIVATE_FROM_C_OBJECT(participant)->getDevices());
}
......@@ -44,6 +44,7 @@
F(MediaSessionParams, CallParams) \
F(Participant, Participant) \
F(ParticipantImdnState, ParticipantImdnState) \
F(ParticipantDevice, ParticipantDevice) \
F(SearchResult, SearchResult)
#define L_REGISTER_SUBTYPES(F) \
......
......@@ -534,11 +534,10 @@ LinphoneReason ChatMessagePrivate::receive () {
}
// Sender Authentication
// If LIMEv2 enabled, the authenticatedFromAddress is the decrypted CPIM From Address
// If LIMEv2 disabled, the authenticatedFromAddress must be set here as the SIP From Address
// If LIMEv2 disabled in group chat room the sender authentication is disabled
// TODO replace me with future "chatRoom->isEncrypted()" API because LIMEv2 will always be enabled
if (!core->limeX3dhEnabled()) {
// In secured chat rooms, the authenticatedFromAddress is already the decrypted CPIM From Address
// In plain text basic chat rooms, the authenticatedFromAddress must be set here as the SIP From Address
// In plain text group chat rooms the sender authentication is disabled
if (!(q->getSharedFromThis()->getChatRoom()->getCapabilities() & ChatRoom::Capabilities::Encrypted)) {
if (q->getSharedFromThis()->getChatRoom()->getCapabilities() & ChatRoom::Capabilities::Basic) {
IdentityAddress sipFromAddress = q->getSharedFromThis()->getFromAddress();
setAuthenticatedFromAddress(sipFromAddress);
......
......@@ -78,7 +78,7 @@ public:
}
migrationRealTime = currentRealTime;
clientGroupChatRoom = static_pointer_cast<ClientGroupChatRoom>(
chatRoom->getCore()->getPrivate()->createClientGroupChatRoom(chatRoom->getSubject(), "", Content(), false)
chatRoom->getCore()->getPrivate()->createClientGroupChatRoom(chatRoom->getSubject(), "", Content(), false, false) // TODO encrypted = false because chatroom migration
);
clientGroupChatRoom->getPrivate()->setCallSessionListener(this);
clientGroupChatRoom->getPrivate()->setChatRoomListener(this);
......
......@@ -69,6 +69,8 @@ shared_ptr<CallSession> ClientGroupChatRoomPrivate::createSession () {
csp.addCustomContactParameter("text");
if (capabilities & ClientGroupChatRoom::Capabilities::OneToOne)
csp.addCustomHeader("One-To-One-Chat-Room", "true");
if (capabilities & ClientGroupChatRoom::Capabilities::Encrypted)
csp.addCustomHeader("End-To-End-Encrypted", "true");
ParticipantPrivate *dFocus = qConference->getPrivate()->focus->getPrivate();
shared_ptr<CallSession> session = dFocus->createSession(*q, &csp, false, callSessionListener);
......@@ -248,9 +250,11 @@ ClientGroupChatRoom::ClientGroupChatRoom (
const string &uri,
const IdentityAddress &me,
const string &subject,
const Content &content
const Content &content,
bool encrypted
) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ConferenceId(IdentityAddress(), me)),
RemoteConference(core, me, nullptr) {
L_D();
L_D_T(RemoteConference, dConference);
IdentityAddress focusAddr(uri);
......@@ -260,6 +264,9 @@ RemoteConference(core, me, nullptr) {
list<IdentityAddress> identAddresses = Conference::parseResourceLists(content);
for (const auto &addr : identAddresses)
dConference->participants.push_back(make_shared<Participant>(this, addr));
if (encrypted)
d->capabilities |= ClientGroupChatRoom::Capabilities::Encrypted;
}
ClientGroupChatRoom::ClientGroupChatRoom (
......@@ -277,6 +284,7 @@ RemoteConference(core, me->getAddress(), nullptr) {
L_D_T(RemoteConference, dConference);
d->capabilities |= capabilities & ClientGroupChatRoom::Capabilities::OneToOne;
d->capabilities |= capabilities & ClientGroupChatRoom::Capabilities::Encrypted;
const IdentityAddress &peerAddress = conferenceId.getPeerAddress();
dConference->focus = make_shared<Participant>(this, peerAddress);
dConference->focus->getPrivate()->addDevice(peerAddress);
......@@ -331,19 +339,26 @@ ClientGroupChatRoom::CapabilitiesMask ClientGroupChatRoom::getCapabilities () co
}
ChatRoom::SecurityLevel ClientGroupChatRoom::getSecurityLevel () const {
L_D();
if (!(d->capabilities & ClientGroupChatRoom::Capabilities::Encrypted)) {
return AbstractChatRoom::SecurityLevel::ClearText;
}
bool isSafe = true;
for (const auto &participant : getParticipants()) {
auto level = participant->getSecurityLevel();
switch (level) {
case AbstractChatRoom::SecurityLevel::Unsafe:
lInfo() << "Chatroom SecurityLevel = Unsafe";
return level; // if one device is Unsafe the whole participant is Unsafe (red)
return level; // if one device is Unsafe the whole participant is Unsafe
case AbstractChatRoom::SecurityLevel::ClearText:
lInfo() << "Chatroom securityLevel = ClearText";
return level; // if one device is ClearText the whole participant is ClearText
case AbstractChatRoom::SecurityLevel::Encrypted:
isSafe = false; // if one device is Encrypted the whole participant is Encrypted (orange)
isSafe = false; // if one device is Encrypted the whole participant is Encrypted
break;
case AbstractChatRoom::SecurityLevel::Safe:
break; // if all devices are Safe the whole participant is Safe (green)
break; // if all devices are Safe the whole participant is Safe
}
}
if (isSafe) {
......@@ -454,6 +469,15 @@ void ClientGroupChatRoom::addParticipants (
"misc", "one_to_one_chat_room_enabled", TRUE))
) {
d->capabilities |= ClientGroupChatRoom::Capabilities::OneToOne;
const IdentityAddress &me = getMe()->getAddress();
const IdentityAddress &participant = addresses.front();
bool encrypted = getCapabilities() & ClientGroupChatRoom::Capabilities::Encrypted;
auto existingChatRoom = getCore()->findOneToOneChatRoom(getLocalAddress(), participant, encrypted);
if (existingChatRoom) {
lError() << "Trying to create already existing " << (encrypted ? "" : "non-") << "encrypted one-to-one chatroom with participants: " <<
me << ", " << participant;
return;
}
}
if (getState() == ChatRoom::State::Instantiated) {
......
......@@ -47,7 +47,8 @@ public:
const std::string &factoryUri,
const IdentityAddress &me,
const std::string &subject,
const Content &content
const Content &content,
bool encrypted = false
);
ClientGroupChatRoom (
......
......@@ -485,7 +485,10 @@ void ServerGroupChatRoomPrivate::addCompatibleParticipants (const IdentityAddres
q->addParticipants(compatibleParticipants, nullptr, false);
if ((capabilities & ServerGroupChatRoom::Capabilities::OneToOne) && (q->getParticipantCount() == 2)) {
// Insert the one-to-one chat room in Db if participants count is 2.
q->getCore()->getPrivate()->mainDb->insertOneToOneConferenceChatRoom(q->getSharedFromThis());
bool encrypted = false;
if ((capabilities & ServerGroupChatRoom::Capabilities::Encrypted))
encrypted = true;
q->getCore()->getPrivate()->mainDb->insertOneToOneConferenceChatRoom(q->getSharedFromThis(), encrypted);
}
}
}
......@@ -638,6 +641,8 @@ void ServerGroupChatRoomPrivate::inviteDevice (const shared_ptr<ParticipantDevic
CallSessionParams csp;
if (capabilities & ServerGroupChatRoom::Capabilities::OneToOne)
csp.addCustomHeader("One-To-One-Chat-Room", "true");
if (capabilities & ServerGroupChatRoom::Capabilities::Encrypted)
csp.addCustomHeader("End-To-End-Encrypted", "true");
session = participant->getPrivate()->createSession(*q, &csp, false, this);
session->configure(LinphoneCallOutgoing, nullptr, nullptr, qConference->getPrivate()->conferenceAddress, device->getAddress());
device->setSession(session);
......@@ -816,6 +821,11 @@ LocalConference(getCore(), IdentityAddress(linphone_proxy_config_get_conference_
const char *oneToOneChatRoomStr = sal_custom_header_find(op->getRecvCustomHeaders(), "One-To-One-Chat-Room");
if (oneToOneChatRoomStr && (strcmp(oneToOneChatRoomStr, "true") == 0))
d->capabilities |= ServerGroupChatRoom::Capabilities::OneToOne;
const char *endToEndEncryptedStr = sal_custom_header_find(op->getRecvCustomHeaders(), "End-To-End-Encrypted");
if (endToEndEncryptedStr && (strcmp(endToEndEncryptedStr, "true") == 0))
d->capabilities |= ServerGroupChatRoom::Capabilities::Encrypted;
shared_ptr<CallSession> session = getMe()->getPrivate()->createSession(*this, nullptr, false, d);
session->configure(LinphoneCallIncoming, nullptr, op, Address(op->getFrom()), Address(op->getTo()));
getCore()->getPrivate()->localListEventHandler->addHandler(dConference->eventHandler.get());
......
......@@ -150,6 +150,15 @@ ChatMessageModifier::Result LimeX3DHEncryptionEngine::processOutgoingMessage (
const IdentityAddress &peerAddress = chatRoom->getPeerAddress();
shared_ptr<const string> recipientUserId = make_shared<const string>(peerAddress.getAddressWithoutGruu().asString());
// Check if chatroom is encrypted or not
shared_ptr<ClientGroupChatRoom> cgcr = static_pointer_cast<ClientGroupChatRoom>(chatRoom);
if (cgcr->getCapabilities() & ChatRoom::Capabilities::Encrypted) {
lInfo() << "LIMEv2 this chatroom is encrypted, proceed to encrypt outgoing message";
} else {
lWarning() << "LIMEv2 this chatroom is not encrypted, no need encrypt outgoing message";
return ChatMessageModifier::Result::Skipped;
}
// Reject message in unsafe chatroom if not allowed
if (linphone_config_get_int(linphone_core_get_config(chatRoom->getCore()->getCCore()), "lime", "allow_message_in_unsafe_chatroom", 0) == 0) {
if (chatRoom->getSecurityLevel() == ClientGroupChatRoom::SecurityLevel::Unsafe) {
......@@ -499,7 +508,6 @@ AbstractChatRoom::SecurityLevel LimeX3DHEncryptionEngine::getSecurityLevel (cons