BUGZ-319 - Add 'Installed By' username to installed content section on

settings.
This commit is contained in:
Roxanne Skelly 2019-07-29 16:25:51 -07:00
parent 4722f55c51
commit b4fee1140c
12 changed files with 64 additions and 48 deletions

View file

@ -130,12 +130,12 @@ $(document).ready(function(){
html += "<td class='data'><strong>File Name</strong></td>";
html += "<td class='data'><strong>Created</strong></td>";
html += "<td class='data'><strong>Installed</strong></td>";
//html += "<td class='data'><strong>Installed By</strong></td></tr>";
html += "<td class='data'><strong>Installed By</strong></td></tr>";
html += "<tr><td class='data' id='" + INSTALLED_CONTENT_NAME_ID + "'/>";
html += "<td class='data' id='" + INSTALLED_CONTENT_FILENAME_ID + "'/>";
html += "<td class='data' id='" + INSTALLED_CONTENT_CREATED_ID + "'/>";
html += "<td class='data' id='" + INSTALLED_CONTENT_INSTALLED_ID + "'/>";
//html += "<td class='data' id='" + INSTALLED_CONTENT_INSTALLED_BY_ID + "'/></tr>";
html += "<td class='data' id='" + INSTALLED_CONTENT_INSTALLED_BY_ID + "'/></tr>";
html += "</tbody></table>";
$('#' + Settings.INSTALLED_CONTENT + ' .panel-body').html(html);
}
@ -379,7 +379,7 @@ $(document).ready(function(){
$('#' + INSTALLED_CONTENT_FILENAME_ID).text(data.installed_content.filename);
$('#' + INSTALLED_CONTENT_CREATED_ID).text(data.installed_content.creation_time ? moment(data.installed_content.creation_time).format('lll') : "");
$('#' + INSTALLED_CONTENT_INSTALLED_ID).text(data.installed_content.install_time ? moment(data.installed_content.install_time).format('lll') : "");
//$('#' + INSTALLED_CONTENT_INSTALLED_BY_ID).text(data.installed_content.installed_by);
$('#' + INSTALLED_CONTENT_INSTALLED_BY_ID).text(data.installed_content.installed_by);
// update the progress bars for current restore status
if (data.status.isRecovering) {

View file

@ -278,7 +278,7 @@ void AssetsBackupHandler::createBackup(const QString& backupName, QuaZip& zip) {
_backups.emplace_back(backupName, mappings, false);
}
std::pair<bool, QString> AssetsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) {
std::pair<bool, QString> AssetsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip, const QString& username, const QString& sourceFilename) {
Q_ASSERT(QThread::currentThread() == thread());
if (operationInProgress()) {

View file

@ -38,7 +38,7 @@ public:
void loadBackup(const QString& backupName, QuaZip& zip) override;
void loadingComplete() override;
void createBackup(const QString& backupName, QuaZip& zip) override;
std::pair<bool, QString> recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) override;
std::pair<bool, QString> recoverBackup(const QString& backupName, QuaZip& zip, const QString& username, const QString& sourceFilename) override;
void deleteBackup(const QString& backupName) override;
void consolidateBackup(const QString& backupName, QuaZip& zip) override;
bool isCorruptedBackup(const QString& backupName) override;

View file

@ -30,7 +30,7 @@ public:
virtual void loadBackup(const QString& backupName, QuaZip& zip) = 0;
virtual void loadingComplete() = 0;
virtual void createBackup(const QString& backupName, QuaZip& zip) = 0;
virtual std::pair<bool, QString> recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) = 0;
virtual std::pair<bool, QString> recoverBackup(const QString& backupName, QuaZip& zip, const QString& username, const QString& sourceFilename) = 0;
virtual void deleteBackup(const QString& backupName) = 0;
virtual void consolidateBackup(const QString& backupName, QuaZip& zip) = 0;
virtual bool isCorruptedBackup(const QString& backupName) = 0;

View file

@ -84,7 +84,7 @@ void ContentSettingsBackupHandler::createBackup(const QString& backupName, QuaZi
}
}
std::pair<bool, QString> ContentSettingsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) {
std::pair<bool, QString> ContentSettingsBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip, const QString& username, const QString& sourceFilename) {
if (!zip.setCurrentFile(CONTENT_SETTINGS_BACKUP_FILENAME)) {
QString errorStr("Failed to find " + CONTENT_SETTINGS_BACKUP_FILENAME + " while recovering backup");
qWarning() << errorStr;
@ -117,7 +117,7 @@ std::pair<bool, QString> ContentSettingsBackupHandler::recoverBackup(const QStri
{ INSTALLED_CONTENT_NAME, archiveJson[INSTALLED_CONTENT_NAME].toString()},
{ INSTALLED_CONTENT_CREATION_TIME, archiveJson[INSTALLED_CONTENT_CREATION_TIME].toVariant().toLongLong() },
{ INSTALLED_CONTENT_INSTALL_TIME, QDateTime::currentDateTime().currentMSecsSinceEpoch() },
{ INSTALLED_CONTENT_INSTALLED_BY, "" }
{ INSTALLED_CONTENT_INSTALLED_BY, username }
};
jsonObject.insert(INSTALLED_CONTENT, installed_content);

View file

@ -28,7 +28,7 @@ public:
void createBackup(const QString& backupName, QuaZip& zip) override;
std::pair<bool, QString> recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) override;
std::pair<bool, QString> recoverBackup(const QString& backupName, QuaZip& zip, const QString& username, const QString& sourceFilename) override;
void deleteBackup(const QString& backupName) override {}

View file

@ -279,7 +279,7 @@ void DomainContentBackupManager::deleteBackup(MiniPromise::Promise promise, cons
});
}
bool DomainContentBackupManager::recoverFromBackupZip(const QString& backupName, QuaZip& zip, const QString& sourceFilename, bool rollingBack) {
bool DomainContentBackupManager::recoverFromBackupZip(const QString& backupName, QuaZip& zip, const QString& username, const QString& sourceFilename, bool rollingBack) {
if (!zip.open(QuaZip::Mode::mdUnzip)) {
qWarning() << "Failed to unzip file: " << backupName;
return false;
@ -290,7 +290,7 @@ bool DomainContentBackupManager::recoverFromBackupZip(const QString& backupName,
for (auto& handler : _backupHandlers) {
bool success;
QString errorStr;
std::tie(success, errorStr) = handler->recoverBackup(backupName, zip, sourceFilename);
std::tie(success, errorStr) = handler->recoverBackup(backupName, zip, username, sourceFilename);
if (!success) {
if (!rollingBack) {
_recoveryError = errorStr;
@ -304,7 +304,7 @@ bool DomainContentBackupManager::recoverFromBackupZip(const QString& backupName,
}
}
void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise, const QString& backupName) {
void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise, const QString& backupName, const QString& username) {
if (_isRecovering) {
promise->resolve({
{ "success", false }
@ -314,7 +314,7 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise,
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "recoverFromBackup", Q_ARG(MiniPromise::Promise, promise),
Q_ARG(const QString&, backupName));
Q_ARG(const QString&, backupName), Q_ARG(const QString&, username));
return;
}
@ -327,7 +327,7 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise,
if (backupFile.open(QIODevice::ReadOnly)) {
QuaZip zip { &backupFile };
success = recoverFromBackupZip(backupName, zip, backupName);
success = recoverFromBackupZip(backupName, zip, username, backupName);
backupFile.close();
} else {
@ -340,11 +340,11 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise,
});
}
void DomainContentBackupManager::recoverFromUploadedBackup(MiniPromise::Promise promise, QByteArray uploadedBackup) {
void DomainContentBackupManager::recoverFromUploadedBackup(MiniPromise::Promise promise, QByteArray uploadedBackup, QString username) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "recoverFromUploadedBackup", Q_ARG(MiniPromise::Promise, promise),
Q_ARG(QByteArray, uploadedBackup));
Q_ARG(QByteArray, uploadedBackup), Q_ARG(QString, username));
return;
}
@ -355,17 +355,17 @@ void DomainContentBackupManager::recoverFromUploadedBackup(MiniPromise::Promise
QuaZip uploadedZip { &uploadedBackupBuffer };
QString backupName = MANUAL_BACKUP_PREFIX + "uploaded.zip";
bool success = recoverFromBackupZip(backupName, uploadedZip, QString());
bool success = recoverFromBackupZip(backupName, uploadedZip, username, QString());
promise->resolve({
{ "success", success }
});
}
void DomainContentBackupManager::recoverFromUploadedFile(MiniPromise::Promise promise, QString uploadedFilename, QString sourceFilename) {
void DomainContentBackupManager::recoverFromUploadedFile(MiniPromise::Promise promise, QString uploadedFilename, const QString username, QString sourceFilename) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "recoverFromUploadedFile", Q_ARG(MiniPromise::Promise, promise),
Q_ARG(QString, uploadedFilename), Q_ARG(QString, sourceFilename));
Q_ARG(QString, uploadedFilename), Q_ARG(QString, username), Q_ARG(QString, sourceFilename));
return;
}
@ -382,7 +382,7 @@ void DomainContentBackupManager::recoverFromUploadedFile(MiniPromise::Promise pr
QString backupName = MANUAL_BACKUP_PREFIX + "uploaded.zip";
bool success = recoverFromBackupZip(backupName, uploadedZip, sourceFilename);
bool success = recoverFromBackupZip(backupName, uploadedZip, username, sourceFilename);
if (!success) {
@ -394,7 +394,7 @@ void DomainContentBackupManager::recoverFromUploadedFile(MiniPromise::Promise pr
QuaZip uploadedZip { &uploadedFile };
QString backupName = MANUAL_BACKUP_PREFIX + "uploaded.zip";
recoverFromBackupZip(backupName, uploadedZip, sourceFilename, true);
recoverFromBackupZip(backupName, uploadedZip, sourceFilename, username, true);
}
}

View file

@ -95,9 +95,9 @@ public:
public slots:
void getAllBackupsAndStatus(MiniPromise::Promise promise);
void createManualBackup(MiniPromise::Promise promise, const QString& name);
void recoverFromBackup(MiniPromise::Promise promise, const QString& backupName);
void recoverFromUploadedBackup(MiniPromise::Promise promise, QByteArray uploadedBackup);
void recoverFromUploadedFile(MiniPromise::Promise promise, QString uploadedFilename, QString sourceFilename);
void recoverFromBackup(MiniPromise::Promise promise, const QString& backupName, const QString& username);
void recoverFromUploadedBackup(MiniPromise::Promise promise, QByteArray uploadedBackup, QString username);
void recoverFromUploadedFile(MiniPromise::Promise promise, QString uploadedFilename, QString username, QString sourceFilename);
void deleteBackup(MiniPromise::Promise promise, const QString& backupName);
signals:
@ -119,7 +119,7 @@ protected:
std::pair<bool, QString> createBackup(const QString& prefix, const QString& name);
bool recoverFromBackupZip(const QString& backupName, QuaZip& backupZip, const QString& sourceFilename, bool rollingBack = false);
bool recoverFromBackupZip(const QString& backupName, QuaZip& backupZip, const QString& username, const QString& sourceFilename, bool rollingBack = false);
private slots:
void removeOldConsolidatedBackups();

View file

@ -1957,6 +1957,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
QPointer<HTTPConnection> connectionPtr { connection };
auto nodeList = DependencyManager::get<LimitedNodeList>();
QString username;
auto getSetting = [this](QString keyPath, QVariant& value) -> bool {
@ -2024,7 +2025,9 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
}
// all requests below require a cookie to prove authentication so check that first
if (!isAuthenticatedRequest(connection, url)) {
bool isAuthenticated { false };
std::tie(isAuthenticated, username) = isAuthenticatedRequest(connection);
if (!isAuthenticated) {
// this is not an authenticated request
// return true from the handler since it was handled with a 401 or re-direct to auth
return true;
@ -2361,7 +2364,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
connectionPtr->respond(success ? HTTPConnection::StatusCode200 : HTTPConnection::StatusCode400, docJSON.toJson(),
JSON_MIME_TYPE.toUtf8());
});
_contentManager->recoverFromBackup(deferred, id);
_contentManager->recoverFromBackup(deferred, id, username);
return true;
}
} else if (connection->requestOperation() == QNetworkAccessManager::PutOperation) {
@ -2557,6 +2560,9 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite
int sessionId = sessionIdBytes.toInt();
bool newUpload = itemName == "restore-file" || itemName == "restore-file-chunk-initial" || itemName == "restore-file-chunk-only";
bool isAuthenticated;
QString username;
std::tie(isAuthenticated, username) = isAuthenticatedRequest(connection);
if (filename.endsWith(".zip", Qt::CaseInsensitive)) {
static const QString TEMPORARY_CONTENT_FILEPATH { QDir::tempPath() + "/hifiUploadContent_XXXXXX.zip" };
@ -2591,7 +2597,7 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite
_pendingContentFiles.erase(sessionId);
});
_contentManager->recoverFromUploadedFile(deferred, _pendingFileContent.fileName(), filename);
_contentManager->recoverFromUploadedFile(deferred, _pendingFileContent.fileName(), username, filename);
}
} else if (filename.endsWith(".json", Qt::CaseInsensitive)
|| filename.endsWith(".json.gz", Qt::CaseInsensitive)) {
@ -2604,7 +2610,7 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite
if (itemName == "restore-file" || itemName == "restore-file-chunk-final" || itemName == "restore-file-chunk-only") {
// invoke our method to hand the new octree file off to the octree server
if (!handleOctreeFileReplacement(_pendingUploadedContent, filename, QString())) {
if (!handleOctreeFileReplacement(_pendingUploadedContent, filename, QString(), username)) {
connection->respond(HTTPConnection::StatusCode400);
return false;
}
@ -2680,7 +2686,7 @@ void DomainServer::profileRequestFinished() {
}
}
bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl& url) {
std::pair<bool, QString> DomainServer::isAuthenticatedRequest(HTTPConnection* connection) {
static const QByteArray HTTP_COOKIE_HEADER_KEY = "Cookie";
static const QString ADMIN_USERS_CONFIG_KEY = "admin-users";
@ -2717,7 +2723,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
if (_settingsManager.valueForKeyPath(ADMIN_USERS_CONFIG_KEY).toStringList().contains(profileUsername)) {
// this is an authenticated user
return true;
return { true, profileUsername };
}
// loop the roles of this user and see if they are in the admin-roles array
@ -2727,7 +2733,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
foreach(const QString& userRole, sessionData.getRoles()) {
if (adminRolesArray.contains(userRole)) {
// this user has a role that allows them to administer the domain-server
return true;
return { true, profileUsername };
}
}
}
@ -2735,7 +2741,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
connection->respond(HTTPConnection::StatusCode401, UNAUTHENTICATED_BODY);
// the user does not have allowed username or role, return 401
return false;
return { false, QString() };
} else {
static const QByteArray REQUESTED_WITH_HEADER = "X-Requested-With";
static const QString XML_REQUESTED_WITH = "XMLHttpRequest";
@ -2764,7 +2770,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
}
// we don't know about this user yet, so they are not yet authenticated
return false;
return { false, QString() };
}
} else if (_settingsManager.valueForKeyPath(BASIC_AUTH_USERNAME_KEY_PATH).isValid()) {
// config file contains username and password combinations for basic auth
@ -2793,7 +2799,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
"" : QCryptographicHash::hash(headerPassword.toUtf8(), QCryptographicHash::Sha256).toHex();
if (settingsUsername == headerUsername && hexHeaderPassword == settingsPassword) {
return true;
return { true, headerUsername };
}
}
}
@ -2815,11 +2821,11 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
HTTPConnection::DefaultContentType, basicAuthHeader);
// not authenticated, bubble up false
return false;
return { false, QString() };
} else {
// we don't have an OAuth URL + admin roles/usernames, so all users are authenticated
return true;
return { true, QString() };
}
}
@ -3493,7 +3499,7 @@ void DomainServer::maybeHandleReplacementEntityFile() {
}
}
bool DomainServer::handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name) {
bool DomainServer::handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name, QString username) {
OctreeUtils::RawEntityData data;
if (data.readOctreeDataInfoFromData(octreeFile)) {
data.resetIdAndVersion();
@ -3514,7 +3520,7 @@ bool DomainServer::handleOctreeFileReplacement(QByteArray octreeFile, QString so
{ INSTALLED_CONTENT_NAME, name },
{ INSTALLED_CONTENT_CREATION_TIME, 0 },
{ INSTALLED_CONTENT_INSTALL_TIME, QDateTime::currentDateTime().currentMSecsSinceEpoch() },
{ INSTALLED_CONTENT_INSTALLED_BY, "" }
{ INSTALLED_CONTENT_INSTALLED_BY, username }
};
QJsonObject jsonObject { { INSTALLED_CONTENT, installed_content } };
@ -3539,6 +3545,11 @@ void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer<R
qInfo() << "Received request to replace content from a url";
auto node = DependencyManager::get<LimitedNodeList>()->findNodeWithAddr(message->getSenderSockAddr());
if (node && node->getCanReplaceContent()) {
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
QString username;
if (nodeData) {
username = nodeData->getUsername();
}
// Convert message data into our URL
QString url(message->getMessage());
QUrl modelsURL = QUrl(url, QUrl::StrictMode);
@ -3548,17 +3559,17 @@ void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer<R
qDebug() << "Downloading JSON from: " << modelsURL.toString(QUrl::FullyEncoded);
connect(reply, &QNetworkReply::finished, [this, reply, modelsURL]() {
connect(reply, &QNetworkReply::finished, [this, reply, modelsURL, username]() {
QNetworkReply::NetworkError networkError = reply->error();
if (networkError == QNetworkReply::NoError) {
if (modelsURL.fileName().endsWith(".json.gz")) {
QUrlQuery urlQuery(modelsURL.query(QUrl::FullyEncoded));
QString itemName = urlQuery.queryItemValue(CONTENT_SET_NAME_QUERY_PARAM);
handleOctreeFileReplacement(reply->readAll(), modelsURL.fileName(), itemName);
handleOctreeFileReplacement(reply->readAll(), modelsURL.fileName(), itemName, username);
} else if (modelsURL.fileName().endsWith(".zip")) {
auto deferred = makePromise("recoverFromUploadedBackup");
_contentManager->recoverFromUploadedBackup(deferred, reply->readAll());
_contentManager->recoverFromUploadedBackup(deferred, reply->readAll(), username);
}
} else {
qDebug() << "Error downloading JSON from specified file: " << modelsURL;
@ -3569,7 +3580,12 @@ void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer<R
void DomainServer::handleOctreeFileReplacementRequest(QSharedPointer<ReceivedMessage> message) {
auto node = DependencyManager::get<NodeList>()->nodeWithLocalID(message->getSourceID());
if (node->getCanReplaceContent()) {
handleOctreeFileReplacement(message->readAll(), QString(), QString());
if (node && node->getCanReplaceContent()) {
QString username;
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
if (nodeData) {
username = nodeData->getUsername();
}
handleOctreeFileReplacement(message->readAll(), QString(), QString(), username);
}
}

View file

@ -99,7 +99,7 @@ private slots:
void handleDomainContentReplacementFromURLRequest(QSharedPointer<ReceivedMessage> message);
void handleOctreeFileReplacementRequest(QSharedPointer<ReceivedMessage> message);
bool handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name);
bool handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name, QString username);
void processOctreeDataRequestMessage(QSharedPointer<ReceivedMessage> message);
void processOctreeDataPersistMessage(QSharedPointer<ReceivedMessage> message);
@ -194,7 +194,7 @@ private:
QUrl oauthRedirectURL();
QUrl oauthAuthorizationURL(const QUuid& stateUUID = QUuid::createUuid());
bool isAuthenticatedRequest(HTTPConnection* connection, const QUrl& url);
std::pair<bool, QString> isAuthenticatedRequest(HTTPConnection* connection);
QNetworkReply* profileRequestGivenTokenReply(QNetworkReply* tokenReply);
Headers setupCookieHeadersFromProfileReply(QNetworkReply* profileReply);

View file

@ -57,7 +57,7 @@ void EntitiesBackupHandler::createBackup(const QString& backupName, QuaZip& zip)
}
}
std::pair<bool, QString> EntitiesBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) {
std::pair<bool, QString> EntitiesBackupHandler::recoverBackup(const QString& backupName, QuaZip& zip, const QString& username, const QString& sourceFilename) {
if (!zip.setCurrentFile(ENTITIES_BACKUP_FILENAME)) {
QString errorStr("Failed to find " + ENTITIES_BACKUP_FILENAME + " while recovering backup");
qWarning() << errorStr;

View file

@ -29,7 +29,7 @@ public:
void createBackup(const QString& backupName, QuaZip& zip) override;
// Recover from a full backup
std::pair<bool, QString> recoverBackup(const QString& backupName, QuaZip& zip, const QString& sourceFilename) override;
std::pair<bool, QString> recoverBackup(const QString& backupName, QuaZip& zip, const QString& username, const QString& sourceFilename) override;
// Delete a skeleton backup
void deleteBackup(const QString& backupName) override {}