void AxoConversation::storeConversation()
{
    SQLiteStoreConv* store = SQLiteStoreConv::getStore();

    const string* data = serialize();

    store->storeConversation(partner_.getName(), deviceId_, localUser_, *data);
    memset_volatile((void*)data->data(), 0, data->size());

    delete data;
}
void AxoConversation::storeStagedMks()
{
    SQLiteStoreConv* store = SQLiteStoreConv::getStore();
    while (!stagedMk->empty()) {
        string mkivmac = stagedMk->front();
        stagedMk->pop_front();
        store->insertStagedMk(partner_.getName(), deviceId_, localUser_, mkivmac);
    }
    delete stagedMk; stagedMk = NULL;

    // Cleanup old MKs
    time_t timestamp = time(0) - MK_STORE_TIME;
    store->deleteStagedMk(timestamp);
}
Exemplo n.º 3
0
static int32_t addMissingMetaData(PtrChangeSet changeSet, const string& groupId, const string& binDeviceId, const uint8_t *updateId, SQLiteStoreConv &store)
{
    int32_t result;
    auto groupShared = store.listGroup(groupId, &result);
    auto group = groupShared.get();

    if (!changeSet->has_updatename()) {
        string name = Utilities::getJsonString(group, GROUP_NAME, "");
        changeSet->mutable_updatename()->set_name(name);
        result = prepareChangeSetClocks(groupId, binDeviceId, changeSet, GROUP_SET_NAME, updateId, store, false);
        if (result < 0) {
            return result;
        }
    }

    if (!changeSet->has_updateavatar()) {
        string avatar = Utilities::getJsonString(group, GROUP_AVATAR, "");
        changeSet->mutable_updateavatar()->set_avatar(avatar);
        result = prepareChangeSetClocks(groupId, binDeviceId, changeSet, GROUP_SET_AVATAR, updateId, store, false);
        if (result < 0) {
            return result;
        }
    }
    if (!changeSet->has_updateburn()) {
        auto sec = static_cast<uint64_t>(Utilities::getJsonInt(group, GROUP_BURN_SEC, 0));
        int32_t mode = Utilities::getJsonInt(group, GROUP_BURN_MODE, 0);
        changeSet->mutable_updateburn()->set_burn_ttl_sec(sec);
        changeSet->mutable_updateburn()->set_burn_mode((GroupUpdateSetBurn_BurnMode)mode);
        result = prepareChangeSetClocks(groupId, binDeviceId, changeSet, GROUP_SET_BURN, updateId, store, false);
        if (result < 0) {
            return result;
        }
    }
    return SUCCESS;
}
Exemplo n.º 4
0
static
#endif
PtrChangeSet getCurrentGroupChangeSet(const string &groupId, SQLiteStoreConv &store)
{
    auto it = currentChangeSets.find(groupId);
    if (it != currentChangeSets.end()) {
        return it->second;
    }
    // no group change set yet. Check if we really have the group
    if (!store.hasGroup(groupId) || ((store.getGroupAttribute(groupId).first & ACTIVE) != ACTIVE)) {
        return PtrChangeSet();
    }

    // Yes, we have this group, create a change set, insert into map, return the pointer
    auto changeSet = make_shared<GroupChangeSet>();
    if (!currentChangeSets.insert(pair<string, PtrChangeSet >(groupId, changeSet)).second) {
        return PtrChangeSet();
    }
    return changeSet;
}
AxoConversation* AxoConversation::loadConversation(const string& localUser, const string& user, const string& deviceId)
{
    SQLiteStoreConv* store = SQLiteStoreConv::getStore();
    if (!store->hasConversation(user, deviceId, localUser)) {
//        cerr << "No conversation: " << localUser << ", user: "******"cannot load conversation" << endl;
        delete conv;
        return NULL;
    }
    conv->deserialize(*data);
    delete data;
    return conv;
}
Exemplo n.º 6
0
static int32_t addExistingMembers(PtrChangeSet changeSet, const string &groupId, SQLiteStoreConv &store)
{
    list<JsonUnique> members;
    int32_t result = store.getAllGroupMembers(groupId, members);
    if (SQL_FAIL(result)) {
        return result;
    }
    for (auto& member: members) {
        string name(Utilities::getJsonString(member.get(), MEMBER_ID, ""));
        addAddNameToChangeSet(changeSet, name, "");
    }
    return SUCCESS;
}
Exemplo n.º 7
0
int32_t zina::storeLocalVectorClock(SQLiteStoreConv &store, const string& groupId, GroupUpdateType type, const LocalVClock &vectorClock)
{
    LOGGER(DEBUGGING, __func__, " -->");

    if (type == TYPE_NONE || !GroupUpdateType_IsValid(type)) {
        return WRONG_UPDATE_TYPE;
    }

    string serializedData;
    if (!vectorClock.SerializeToString(&serializedData)) {
        return GENERIC_ERROR;
    }

    int32_t result = store.insertReplaceVectorClock(groupId, type, serializedData);
    if (SQL_FAIL(result)) {
        return GROUP_ERROR_BASE + result;   // Error return is -400 + sql code
    }
    LOGGER(DEBUGGING, __func__, " <--");
    return SUCCESS;
}
Exemplo n.º 8
0
static
#endif
PtrChangeSet getPendingGroupChangeSet(const string &groupId, SQLiteStoreConv &store)
{
    // Check if the group's pending change set is cached
    auto found = pendingChangeSets.find(groupId);
    if (found != pendingChangeSets.end()) {
        return found->second;
    }

    // Not cached, get it from persistent storage and cache it
    string changeSetSerialized;
    store.getGroupChangeSet(groupId, &changeSetSerialized);
    if (!changeSetSerialized.empty()) {
        auto changeSet = make_shared<GroupChangeSet>();
        changeSet->ParseFromString(changeSetSerialized);
        pendingChangeSets.insert(pair<string, PtrChangeSet >(groupId, changeSet));
        return changeSet;
    }

    return PtrChangeSet();
}
Exemplo n.º 9
0
int32_t zina::readLocalVectorClock(SQLiteStoreConv &store, const string& groupId, GroupUpdateType type, LocalVClock *vectorClock)
{
    LOGGER(DEBUGGING, __func__, " -->");

    if (type == TYPE_NONE || !GroupUpdateType_IsValid(type)) {
        return WRONG_UPDATE_TYPE;
    }

    string serializedData;
    int32_t result = store.loadVectorClock(groupId, type, &serializedData);
    if (SQL_FAIL(result)) {
        return GROUP_ERROR_BASE + result;   // Error return is -400 + sql code
    }
    if (serializedData.empty()) {
        return NO_VECTOR_CLOCK;
    }
    if (!vectorClock->ParseFromArray(serializedData.data(), static_cast<int32_t>(serializedData.size()))) {
        return NO_VECTOR_CLOCK;
    }
    LOGGER(DEBUGGING, __func__, " <--");
    return SUCCESS;
}
Exemplo n.º 10
0
int32_t MessageCapture::captureSendMessage(const string &receiver, const string &messageId,const string &deviceId,
                                           const string &convState, const string &attributes, bool attachments,
                                           SQLiteStoreConv &store)
{
    LOGGER(DEBUGGING, __func__, " -->");

    LOGGER_BEGIN(INFO)
        string filteredAttributes;
        int32_t result = filterAttributes(attributes, &filteredAttributes);
        if (result < 0) {
            LOGGER(ERROR, __func__, " Cannot parse sent message attributes: ", attributes);
            return result;
        }

        result = store.insertMsgTrace(receiver, messageId, deviceId, convState, filteredAttributes, attachments, false);
        if (SQL_FAIL(result)) {
            LOGGER(ERROR, __func__, " <-- Cannot store sent message trace data.", result);
            return result;
        }
    LOGGER_END
    cleanupTrace(store);
    LOGGER(DEBUGGING, __func__ , " <-- ");
    return SUCCESS;
}
Exemplo n.º 11
0
static void cleanupTrace(SQLiteStoreConv &store )
{
    // Cleanup old traces, currently using the same time as for the Message Key cleanup
    time_t timestamp = time(0) - MK_STORE_TIME;
    store.deleteMsgTrace(timestamp);
}
Exemplo n.º 12
0
TEST(PreKeyStore, Basic)
{
    // Need a key pair here
    const Ec255PublicKey baseKey_1(keyInData_1);
    const Ec255PrivateKey basePriv_1(keyInData_2);
    const DhKeyPair basePair(baseKey_1, basePriv_1);

    string* pk = preKeyJson(3, basePair);

    SQLiteStoreConv* pks = SQLiteStoreConv::getStoreForTesting();
    pks->setKey(std::string((const char*)keyInData, 32));
    pks->openStore(std::string());

    string* pk_1 = pks->loadPreKey(3);
    ASSERT_EQ(NULL, pk_1) <<  "Some data in an empty store?";

    pks->storePreKey(3, *pk);
    ASSERT_TRUE(pks->containsPreKey(3));

    pks->storePreKey(3, *pk);
    ASSERT_TRUE(pks->getSqlCode() == SQLITE_CONSTRAINT) << pks->getLastError();

    pk_1 = pks->loadPreKey(3);
    ASSERT_EQ(*pk, *pk_1);
    delete pk_1;

    pks->removePreKey(3);
    ASSERT_FALSE(pks->containsPreKey(3));

    SQLiteStoreConv::closeStoreForTesting(pks);
}
Exemplo n.º 13
0
int32_t MessageCapture::loadCapturedMsgs(const string &name, const string &messageId,
                                         const string &deviceId, SQLiteStoreConv &store,
                                         list<StringUnique> &traceRecords)
{
    return store.loadMsgTrace(name, messageId, deviceId, traceRecords);
}
Exemplo n.º 14
0
static int64_t t_sendJSONMessage( const char *msg,  bool toSibling, bool normalMsg, const char *attachment, const char *attributes){
   
   char bufValue[1024];
   int findJSonToken(const char *p, int iPLen, const char *key, char *resp, int iMaxLen);
   int l=findJSonToken(msg,(int)strlen(msg),"message",&bufValue[0],sizeof(bufValue)-1);
   if(l>0 && strcmp(bufValue, "*##*delKey*")==0){
      std::string own = axoAppInterface->getOwnUser();
      SQLiteStoreConv* store = SQLiteStoreConv::getStore();
      l = findJSonToken(msg,(int)strlen(msg),"recipient",&bufValue[0],sizeof(bufValue)-1);
      if(l>0)
         store->deleteConversationsName(std::string(bufValue,l) , own);
      return 0;
   }

   std::string message(msg);
   
   std::string s_attachment;
   std::string s_attributes;
   
   if(attachment){
      s_attachment.assign(attachment);
   }
   
   if(attributes){
      s_attributes.assign(attributes);
   }
   
   CTMutexAutoLock _a(_sendMutex);

#if 1
   //this is tmp shortcut to support old API from UI
   int32_t result = 0;
    
    unique_ptr<list<unique_ptr<PreparedMessageData> > > deviceList;
    
    if (toSibling)
    {
       deviceList = axoAppInterface->prepareMessageSiblings(message, s_attachment, s_attributes, normalMsg, &result);
    } else
    {
        deviceList = axoAppInterface->prepareMessageNormal(message, s_attachment, s_attributes, normalMsg, &result);
    }
   
   if(result != SUCCESS ){
      
      if(result != NO_DEVS_FOUND){//this not fail
         return 0;
      }
      return 0;
   }
   return t_sendMessageToEveryDevice(move(deviceList));
   

#else
   
   std::vector<int64_t>* msgIds = axoAppInterface->sendMessage(message, s_attachment, s_attributes);
   
   if (msgIds == NULL || msgIds->empty()) {
      delete msgIds;
      return 0;
   }
   
   int64_t ret = 0;
   for(int i = 0; !ret && i < msgIds->size(); i++){
      ret = msgIds->at(i);
   }
   
   delete msgIds;
   
   return ret;
#endif


}
Exemplo n.º 15
0
/**
 * iOS-specific CTAxoInterfaceBase::sharedInstance main initializer.
 *
 * Called by the t_initAxolotl initializer helper function on first
 * on first access of the CTAxoInterfaceBase::sharedInstance, this 
 * function initializes the local AppInterfaceImpl axoAppInterface instance.
 */
static int _initAxolotl(const char *db, const char *pw, int pwLen, const char *name, const char *api_key, const char *devid){

   if(axoAppInterface)
       return 0;

   if (name == NULL)
      return -10;

   if (api_key == NULL)
      return -12;
   
   int nameLen = (int)strlen(name);
   
   if (nameLen == 0)
      return -11;

   int authLen = (int)strlen(api_key);
   
   if (authLen == 0)
      return -13;
   
   if (pw == NULL)
      return -14;
    
   if (pwLen != 32)
      return -15;
    
    // It is an error for SPi to attempt to initialize 
    // the axo instance with a null/empty db path string.
    if (db == NULL || strcmp(db,"") == 0) {
        t_logf(log_events, __FUNCTION__,"Error: store->openStore called "
               "with empty or nil database path");        
        exitWithFatalErrorMsg("Unable to open database:\n Path not specified");
        return -1;
    }
    
   int isFileExists(const char *fn);
   int firstStart = !isFileExists(db);

   std::string dbPw((const char*)pw, pwLen);
   
   // initialize and open the persitent store singleton instance   
   SQLiteStoreConv* store = SQLiteStoreConv::getStore();
    
   store->setKey(dbPw);
       
    // Log file protection attributes on the db path
    void log_file_protection_prop(const char *fn);
    log_file_protection_prop(db);

    // Always call to set NSFileProtectionNone on db path
    // (this is a no-op if already set)
    setFileBackgroundReadable(db);
    
    int sql_code = store->openStore(std::string (db));
    
    if(sql_code == 0)
        zinaDatabaseWasOpened();
    else {
        t_logf(log_events, __FUNCTION__,"Error: store->openStore failed: %d", sql_code);
        
        char msg[100];
        sprintf(msg, "%s %d", "Unable to open database.\nError: ", sql_code);
        exitWithFatalErrorMsg(msg);
        
        return -1;
    }          
   
  // store->resetStore();
    
   auto ownAxoConv = ZinaConversation::loadLocalConversation(name,*store);

   if (!ownAxoConv->isValid()) {  // no yet available, create one. An own conversation has the same local and remote name, empty device id

       KeyPairUnique idKeyPair = EcCurve::generateKeyPair(EcCurveTypes::Curve25519);
       ownAxoConv->setDHIs(move(idKeyPair));
       ownAxoConv->storeConversation(*store);
   }
   
   axoAppInterface = new AppInterfaceImpl(std::string((const char*)name, nameLen),
                                          std::string((const char*)api_key, authLen),
                                          std::string(devid),
                                          receiveMessage,   messageStateReport,notifyCallback,
                                          receiveGroupMessage, receiveGroupCommand, groupStateReport);
    

    if(drFlags.length()>0){
        axoAppInterface->setDataRetentionFlags(drFlags);
        axoAppInterface->setS3Helper(drISOn ? s3Helper: NULL);
    }
    else{
        char *loadFile(const  char *fn, int &iLen);
        
        int drl=0,drOFl=0;
        char * drF = loadFile(t_getDRJsonFlagFN(0), drl);
        char * drOnOff = loadFile(t_getDRJsonFlagFN(1), drOFl);
        
        if(drl && drF)axoAppInterface->setDataRetentionFlags(string(drF,drl));
        if(drOnOff)axoAppInterface->setS3Helper(drOnOff[0]=='1' ? s3Helper: NULL);
        
        if(drF)delete drF;
        if(drOnOff)delete drOnOff;
    
    }
    
   sipTransport = new SipTransport(axoAppInterface);
   sipTransport->setSendDataFunction(sendDataFuncAxo);
   
   axoAppInterface->setTransport(sipTransport);
   axoAppInterface->setHttpHelper(httpHelper);

   zinaHttpHelperSet = true;

   void tryRegisterAxolotl(int firstStart, int iForce);

   tryRegisterAxolotl(firstStart, 0);
   
   if(!firstStart && mustAddPrekeyCnt){
      axoAppInterface->newPreKeys(mustAddPrekeyCnt);
      mustAddPrekeyCnt = 0;
   }
   
   return 1;
}
Exemplo n.º 16
0
void SipTransport::notifyAxo(const uint8_t* data, size_t length)
{
    LOGGER(DEBUGGING, __func__, " -->");
    string info((const char*)data, length);
    /*
     * notify call back from SIP:
     *   - parse data from SIP, get name and devices
     *   - check for new devices (store->hasConversation() )
     *   - if a new device was found call appInterface_->notifyCallback(...)
     *     NOTE: the notifyCallback function in app should return ASAP, queue/trigger actions only
     *   - done
     */

    size_t found = info.find(':');
    if (found == string::npos)        // No colon? No name -> return
        return;

    string name = info.substr(0, found);
    size_t foundAt = name.find('@');
    if (foundAt != string::npos) {
        name = name.substr(0, foundAt);
    }

    string devIds = info.substr(found + 1);
    string devIdsSave(devIds);

    // This is a check if the SIP server already sent the same notify string for a name
    map<string, string>::iterator it;
    it = seenIdStringsForName.find(name);
    if (it != seenIdStringsForName.end()) {
        // Found an entry, check if device ids match, if yes -> return, already processed,
        // if no -> delete the entry, continue processing which will add the new entry.
        if (it->second == devIdsSave) {
            return;
        }
        else {
            seenIdStringsForName.erase(it);
        }
    }
    pair<map<string, string>::iterator, bool> ret;
    ret = seenIdStringsForName.insert(pair<string, string>(name, devIdsSave));
    if (!ret.second) {
        LOGGER(ERROR, "Caching of notified device ids failed: ", name, ", ", devIdsSave);
    }

    const bool isSibling = appInterface_->getOwnUser() == name;

    size_t pos = 0;
    string devId;
    SQLiteStoreConv* store = SQLiteStoreConv::getStore();

    size_t numReportedDevices = 0;
    bool newDevice = false;
    while ((pos = devIds.find(';')) != string::npos) {
        devId = devIds.substr(0, pos);
        devIds.erase(0, pos + 1);
        if (Zeros.compare(0, devId.size(), devId) == 0) {
            continue;
        }
        if (isSibling && appInterface_->getOwnDeviceId() == devId) {
            continue;
        }
        numReportedDevices++;
        if (!store->hasConversation(name, devId, appInterface_->getOwnUser())) {
            newDevice = true;
            break;
        }
    }
    list<StringUnique> devicesDb;
    store->getLongDeviceIds(name, appInterface_->getOwnUser(), devicesDb);
    size_t numKnownDevices = devicesDb.size();

    // If we saw a new device or the number of reported and known devices differs the user
    // added or removed a device, re-scan devices
    if (newDevice || numKnownDevices != numReportedDevices) {
        LOGGER(INFO, __func__, " Calling notify callback for: ", name, ", device: ", devIdsSave);
        appInterface_->notifyCallback_(AppInterface::DEVICE_SCAN, name, devIdsSave);
    }
    LOGGER(DEBUGGING, __func__, " <--");
}
list<string>* AxoConversation::loadStagedMks()
{
    SQLiteStoreConv* store = SQLiteStoreConv::getStore();
    list<string>* mks = store->loadStagedMks(partner_.getName(), deviceId_, localUser_);
    return mks;
}
void AxoConversation::deleteStagedMk(string& mkiv)
{
    SQLiteStoreConv* store = SQLiteStoreConv::getStore();
    store->deleteStagedMk(partner_.getName(), deviceId_, localUser_, mkiv);
}