Sleds/cppcore/client/vanaccess.cpp

564 lines
17 KiB
C++
Raw Normal View History

2025-03-13 21:28:38 +00:00
// Copyright (c) 2013, IOnU Security, Inc.
// Copyright (c) 2016, Sequence Logic, Inc. All rights reserved.
#include "vanaccess.h"
#include "eyeinterface.h"
#include "../cppcoreobjects//cloudguardurn.h"
#include "../component/slfile.h"
#include "../internal.h"
#include "jsonobject.h"
#include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
#include <sstream>
#include <cstdio>
#include <set>
#ifdef WIN32
#include <io.h>
#include <direct.h>
#else
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#endif
using namespace sequencelogic;
namespace
{
void listFilesDeep(const File &rootDir, std::vector<File> &files);
void removeFiles(const std::string &dir);
void removeDirsDeep(const File &rootDir);
};
namespace sequencelogic
{
class VanAccessData
{
public:
VanAccessData() {}
~VanAccessData() {}
std::string _VANRootDir;
std::string _VANIntDir;
std::string _curVAN;
std::string _devURN;
// Check VAN id...
bool isValidVANid(const std::string &van) const
{
CloudGuardURN vanURN(van);
return (vanURN.getType() != CloudGuardURN::URN_TYPE::INVALID);
}
// Check if a directory exists. If not, create it. If we can't, return false.
bool checkAndCreateDir(std::string dir) const
{
if (dir == "")
return false;
if (*dir.rbegin() != File::DIR_SEP)
dir += File::DIR_SEP;
bool bRetVal = true;
// Create the full path.
File tmpFile (dir);
bRetVal = tmpFile.mkdirs();
return bRetVal;
}
};
};
const char VanAccess::VAN_CONFIG_JSON[] = "van-config.json"; // VAN config filename
const char VanAccess::LAST_ACTIVE_USER[] = "last_active_user.json"; // The last "active" user filename. This is stored at the internal directory root.
VanAccess::VanAccess() : _pData(new VanAccessData())
{
}
VanAccess::~VanAccess()
{
}
/**
* Set a VAN's data root directory.
*
* @param rootDir The root directory to set.
*/
bool VanAccess::setVANDataRootDirectory(const std::string &rootDir)
{
bool bRetVal = false;
// Just store the VAN id string in our cache. Use the CloudGuardURN class to verify it!
if (_pData->checkAndCreateDir(rootDir))
{
// Check that the directory exists. Now sure if this should actually be an error condition,
// initially provisioned devices
_pData->_VANRootDir = rootDir;
if (*_pData->_VANRootDir.rbegin() != File::DIR_SEP)
_pData->_VANRootDir += File::DIR_SEP;
bRetVal = true;
}
return bRetVal;
}
/**
* Get a VAN's data root directory.
*
* @returns The data root, or an empty string if there is no VAN found. If the root directory is indeed the root
* of a filesystem, the client should set this as "/" in the function above.
*/
std::string VanAccess::getVANDataRootDirectory() const
{
return _pData->_VANRootDir;
}
/**
* Set a VAN's internal directory. This is for private storage for this class.
*
* @param rootDir The internal directory to set.
*/
bool VanAccess::setVANInternalDirectory(const std::string &intDir)
{
bool bRetVal = false;
// Just store the VAN id string in our cache. Use the CloudGuardURN class to verify it!
if (_pData->checkAndCreateDir(intDir))
{
// Check that the directory exists. Now sure if this should actually be an error condition,
// initially provisioned devices
_pData->_VANIntDir = intDir;
if (*_pData->_VANIntDir.rbegin() != File::DIR_SEP)
_pData->_VANIntDir += File::DIR_SEP;
bRetVal = true;
// See if there is a 'last active user' file...
std::string lastActiveUser = _pData->_VANIntDir;
lastActiveUser += LAST_ACTIVE_USER;
JSONObject lastUser;
if (lastUser.LoadFromFile(lastActiveUser) && (lastUser.getJSONString("lastActiveID") != ""))
{
_pData->_devURN = lastUser.getJSONString("lastActiveID");
setCurrentVan(lastUser.getJSONObject("lastActiveVAN").toString());
}
}
return bRetVal;
}
/**
* Get a VAN's internal directory.
*
* @returns The internal directory, or an empty string if there is no VAN found. If the root directory is indeed the root
* of a filesystem, the client should set this as "/" in the function above.
*/
std::string VanAccess::getVANInternalDirectory() const
{
return _pData->_VANIntDir;
}
/**
* Set the current VAN being used by the client.
*
* @param vanObj The current VAN, JSON, containing the VAN ID and alias: "{ "_id":"urn:sl:000000:::", "alias":"TEST SERVER" }"
* @returns True, if VAN ID is valid, and set.
*/
bool VanAccess::setCurrentVan(const std::string &vanObj)
{
bool bRetVal = true;
std::lock_guard<std::mutex> lock(_protectData);
JSONObject van(vanObj);
// Use the internal directory area. If it's not set, fail.
if ((_pData->_VANIntDir != "") &&
!van.empty() && _pData->isValidVANid(van.getJSONString("_id")))
{
ionu_policy_uninstall();
CloudGuardURN vanURN(van.getJSONString("_id"));
std::stringstream tmpFilename;
tmpFilename << _pData->_VANIntDir <<
van.getJSONString("alias", "xxx") << File::DIR_SEP <<
vanURN.getVANID() << File::DIR_SEP <<
VAN_CONFIG_JSON;
File vanCfgFile (tmpFilename.str());
if (!vanCfgFile.exists())
installVAN(vanObj);
_pData->_curVAN = vanObj;
ionu_policy_install(_pData->_curVAN.c_str());
}
else
{
_pData->_curVAN = "";
bRetVal = false;
}
return bRetVal;
}
/**
* Get the current VAN being used by the client.
*
* @returns The current VAN in use, empty string if no current VAN is in use.
*/
std::string VanAccess::getCurrentVan() const
{
std::lock_guard<std::mutex> lock(_protectData);
return _pData->_curVAN;
}
/**
* Get all provisioned VANs on the client. Searches the data root.
*
* @returns A shared pointer to a vector of strings of the provisioned VAN ids.
*/
std::string VanAccess::getProvisionedVANs() const
{
JSONArray retVal;
// See if we have a root directory!
if (_pData->_VANIntDir != "")
{
// Look for all the VAN directories. They better be proper VAN id's!
std::string tmpPath = _pData->_VANIntDir;
if (tmpPath[tmpPath.length()-1] != File::DIR_SEP)
tmpPath += File::DIR_SEP;
File tmpDirFile (tmpPath);
std::vector<File> aliasList;
tmpDirFile.listFiles(aliasList);
// Now, check all the returned directories for proper VAN id...
std::vector<File> vanList;
for (unsigned int i = 0; i < aliasList.size(); ++i)
{
if (!aliasList[i].isDirectory())
continue;
// Now, get all the VANs in the list of returned aliases...
vanList.clear();
aliasList[i].listFiles(vanList);
for (unsigned int j = 0; j < vanList.size(); ++j)
{
std::string tmpVANID = vanList[j].getDirectory();
if (tmpVANID[tmpVANID.size()-1] == File::DIR_SEP) {
// Workaround for Android's lack of 'pop_back'...
//tmpVANID.pop_back();
std::string::reverse_iterator rIter = tmpVANID.rbegin();
++rIter;
tmpVANID.erase(rIter.base());
}
tmpVANID.erase(0, tmpVANID.rfind(File::DIR_SEP)+1);
sequencelogic::CloudGuardURN tmpURN(tmpVANID, "");
if (tmpURN.getType() != sequencelogic::CloudGuardURN::URN_TYPE::INVALID)
{
File vanCfgFile(vanList[j], VAN_CONFIG_JSON);
if (vanCfgFile.exists())
{
JSONObject tmpVAN;
if (tmpVAN.LoadFromFile(vanCfgFile.getAbsolutePath()))
retVal.addElement(tmpVAN);
}
}
}
}
}
return retVal.toString();
}
/**
* For a specific VAN, get a JSON array of provisioned users, on this device.
*
* @param vanObj VAN object, as JSON
* @returns A JSON array with all provisioned users
*/
std::string VanAccess::getProvisionedUsers(const std::string &vanObj) const
{
JSONArray retVal;
if (vanObj != "")
{
JSONObject van(vanObj);
CloudGuardURN vanURN(van.getJSONString("_id"));
std::stringstream tmpDirName;
std::string dir = getVANInternalDirectory(); // This was getVANDataRootDirectory() which is wrong!
tmpDirName << dir << File::DIR_SEP <<
van.getJSONString("alias") << File::DIR_SEP <<
vanURN.getVANID() << File::DIR_SEP;
File vanFile(tmpDirName.str());
if (vanFile.exists())
{
std::vector<File> userList;
vanFile.listFiles(userList);
for (unsigned int i = 0; i < userList.size(); ++i)
{
if (userList[i].isDirectory())
{
File userFile(userList[i].getAbsolutePath(), "sl-keyring.iks.public");
JSONObject userObj;
if (userFile.exists() && userObj.LoadFromFile(userFile.getAbsolutePath()))
retVal.addElement(userObj);
}
}
}
}
return retVal.toString();
}
/**
* For a specific VAN, see if this user is already provisioned.
*
* @param vanObj The VAN to check, as JSON
* @param user User to look for
* @return "" if user is not provisioned, JSON with user props if provisioned.
*/
std::string VanAccess::isProvisionedUser(const std::string &vanObj, const std::string &user) const
{
std::string retVal;
JSONArray provisionedUsers (getProvisionedUsers(vanObj));
for (int i = 0; (retVal == "") && (i < provisionedUsers.getnumelements()); ++i)
{
const JSONObject &userObj = reinterpret_cast<const JSONObject &>(provisionedUsers[i]);
if (userObj.getJSONString("user") == user
|| userObj.getJSONObject("email").getJSONString("primary") == user
){
retVal = userObj.toString();
}
}
return retVal;
}
/**
* Wipe out the specified office, in the current van.
*/
void VanAccess::wipeOffice(const std::string &devUrn)
{
JSONObject curVanObj(getCurrentVan());
if (!curVanObj.empty())
{
CloudGuardURN vanURN(curVanObj.getJSONString("_id"));
CloudGuardURN devURN(devUrn);
std::stringstream tmpDir;
tmpDir << getVANInternalDirectory() << curVanObj.getJSONString("alias") <<
File::DIR_SEP << vanURN.getVANID() <<
File::DIR_SEP << devURN.getPMOID() << File::DIR_SEP;
removeFiles(tmpDir.str());
tmpDir.str("");
tmpDir << getVANDataRootDirectory() << curVanObj.getJSONString("alias") <<
File::DIR_SEP << vanURN.getVANID() <<
File::DIR_SEP << devURN.getPMOID() << File::DIR_SEP;
removeFiles(tmpDir.str());
}
}
/**
* Wipe out the current VAN (wipes ALL offices)
*/
void VanAccess::wipeCurrentVAN()
{
JSONObject curVanObj(getCurrentVan());
if (!curVanObj.empty())
{
JSONArray provisionedUsers (getProvisionedUsers(curVanObj.toString()));
for (int i = 0; i < provisionedUsers.getnumelements(); ++i)
{
const JSONObject &user = reinterpret_cast<const JSONObject &>(provisionedUsers[i]);
wipeOffice(user.getJSONString("urn"));
}
std::stringstream tmpDir;
tmpDir << getVANInternalDirectory() << curVanObj.getJSONString("alias") <<
File::DIR_SEP << CloudGuardURN(curVanObj.getJSONString("_id")).getVANID() << File::DIR_SEP;
removeFiles(tmpDir.str());
tmpDir.str("");
tmpDir << getVANDataRootDirectory() << curVanObj.getJSONString("alias") <<
File::DIR_SEP << CloudGuardURN(curVanObj.getJSONString("_id")).getVANID() << File::DIR_SEP;
removeFiles(tmpDir.str());
}
std::string lastActiveUser = _pData->_VANIntDir;
lastActiveUser += LAST_ACTIVE_USER;
std::remove(lastActiveUser.c_str());
setCurrentVan("");
}
/**
* Wipe out ALL VANs!
*/
void VanAccess::wipe()
{
std::set<std::string> serverPaths;
JSONArray vans (getProvisionedVANs());
for (int i = 0; i < vans.getnumelements(); ++i)
{
const JSONObject &van = reinterpret_cast<const JSONObject &>(vans[i]);
setCurrentVan(van.toString());
wipeCurrentVAN();
std::stringstream tmpDir;
tmpDir << getVANInternalDirectory() << van.getJSONString("alias");
serverPaths.insert(tmpDir.str());
tmpDir.str("");
tmpDir << getVANDataRootDirectory() << van.getJSONString("alias");
serverPaths.insert(tmpDir.str());
}
for (std::set<std::string>::iterator iter = serverPaths.begin(); iter != serverPaths.end(); ++iter)
{
#ifdef WIN32
::_rmdir(iter->c_str());
#else
::rmdir(iter->c_str());
#endif
}
}
/**
* Install a VAN.
*
* @param vanObj The current VAN, JSON, containing the VAN ID and alias: "{ "_id":"urn:sl:000000:::", "alias":"TEST SERVER" }"
* @returns True, if VAN ID is valid, and installed.
*/
bool VanAccess::installVAN (const std::string &vanObj)
{
bool bRetVal = false;
JSONObject van(vanObj);
// Use the internal directory area. If it's not set, fail.
if ((_pData->_VANIntDir != "") &&
!van.empty() && _pData->isValidVANid(van.getJSONString("_id")))
{
CloudGuardURN vanURN(van.getJSONString("_id"));
std::stringstream tmpFilename;
tmpFilename << _pData->_VANIntDir <<
van.getJSONString("alias", "xxx") << File::DIR_SEP <<
vanURN.getVANID() << File::DIR_SEP <<
VAN_CONFIG_JSON;
File vanCfgFile (tmpFilename.str());
vanCfgFile.getParentFile().mkdirs();
bRetVal = van.SaveToFile(vanCfgFile.getAbsolutePath());
}
return bRetVal;
}
/**
* Set the current device ID. This is the ID of the (soon to be) logged in user device.
*
* @param devURN The current device URN.
* @returns true if the URN is valid, and set.
*/
bool VanAccess::setDeviceURN (const std::string &devURN)
{
bool bRetVal = false;
if (_pData->_curVAN != "")
{
CloudGuardURN tmpURN(devURN);
if (tmpURN.getType() != CloudGuardURN::URN_TYPE::INVALID)
{
bRetVal = true;
std::lock_guard<std::mutex> lock(_protectData);
_pData->_devURN = devURN;
JSONObject lastActiveJSON;
lastActiveJSON.setJSONValue("lastActiveID", devURN.c_str());
lastActiveJSON.setJSONValue("lastActiveVAN", JSONObject(_pData->_curVAN));
std::string fileName = _pData->_VANIntDir;
fileName += LAST_ACTIVE_USER;
lastActiveJSON.SaveToFile(fileName);
}
else {
std::lock_guard<std::mutex> lock(_protectData);
_pData->_devURN = "";
}
}
return bRetVal;
}
/**
* Get the current device URN.
*
* @return The currently set device URN.
*/
std::string VanAccess::getDeviceURN() const
{
return _pData->_devURN;
}
namespace
{
void listFilesDeep(const File &rootDir, std::vector<File> &files)
{
std::vector<File> tmpList;
rootDir.listFiles(tmpList);
for (unsigned int i = 0; i < tmpList.size(); ++i)
{
if (tmpList[i].isFile())
files.push_back(tmpList[i]);
else if (tmpList[i].isDirectory())
listFilesDeep(tmpList[i], files);
}
}
void removeFiles(const std::string &dir)
{
if ((dir != "") &&
#ifdef WIN32
(dir.length() > 3) // Don't remove starting from "c:\"
#else
(dir.length() > 1) // Don't remove starting from "/"
#endif
)
{
std::vector<File> files;
listFilesDeep(dir, files);
for (unsigned int i = 0; i < files.size(); ++i)
files[i].deleteFile();
removeDirsDeep(dir);
}
}
void removeDirsDeep(const File &rootDir)
{
std::vector<File> tmpList;
rootDir.listFiles(tmpList);
for (unsigned int i = 0; i < tmpList.size(); ++i)
{
if (tmpList[i].isDirectory())
{
removeDirsDeep(tmpList[i]);
std::string dirName = tmpList[i].getAbsolutePath();
if (*dirName.rbegin() == File::DIR_SEP)
{
// Workaround for Android's lack of pop_back
//dirName.pop_back();
std::string::reverse_iterator rIter = dirName.rbegin();
++rIter;
dirName.erase(rIter.base());
}
#ifdef WIN32
::_rmdir(dirName.c_str());
#else
::rmdir(dirName.c_str());
#endif
}
}
#ifdef WIN32
::_rmdir(rootDir.getAbsolutePath().c_str());
#else
::rmdir(rootDir.getAbsolutePath().c_str());
#endif
}
}