mirror of
https://github.com/outbackdingo/sysadm.git
synced 2026-01-27 02:20:17 +00:00
Get the sysadm server message parsing system all setup for bridge relays (no additional encryption/decryption layer yet)
This commit is contained in:
@@ -31,58 +31,11 @@ public:
|
||||
//User Permissions level
|
||||
bool fullaccess;
|
||||
|
||||
RestInputStruct(QString message = ""){
|
||||
HTTPVERSION = CurHttpVersion; //default value
|
||||
fullaccess = false;
|
||||
if(message.isEmpty()){ return; }
|
||||
//Pull out any REST headers
|
||||
Body = message;
|
||||
//qDebug() << "Raw Message:" << message;
|
||||
if(!message.startsWith("{")){
|
||||
Header = message.section("{",0,0).split("\n");
|
||||
Body = "{"+message.section("{",1, 1000000);
|
||||
}
|
||||
if(!Header.isEmpty()){
|
||||
QString line = Header.takeFirst(); //The first line is special (not a generic header)
|
||||
VERB = line.section(" ",0,0);
|
||||
URI = line.section(" ",1,1);
|
||||
HTTPVERSION = line.section(" ",2,2);
|
||||
//Body = message.remove(Header.join("\n")+"\n"); //chop the headers off the front
|
||||
if(!Header.filter("Authorization:").isEmpty()){
|
||||
line = Header.filter("Authorization:").takeFirst().section("Authorization: ",1,50).simplified();
|
||||
if(line.section(" ",0,0).toLower()=="basic"){
|
||||
//Convert the base64-encoded string to the plain "user:pass" string
|
||||
QByteArray ba;
|
||||
ba.append(line.section(" ",1,1));
|
||||
auth = QByteArray::fromBase64(ba);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Now Parse out the Body into the JSON fields and/or arguments structure
|
||||
Body = Body.simplified(); //remove any extra whitespace on the beginning/end
|
||||
if(Body.startsWith("{") && Body.endsWith("}") ){
|
||||
QJsonDocument doc = QJsonDocument::fromJson(Body.toUtf8());
|
||||
if(!doc.isNull() && doc.isObject() ){
|
||||
//Valid JSON found
|
||||
if(doc.object().contains("namespace") ){ namesp = doc.object().value("namespace").toString(); }
|
||||
if(doc.object().contains("name") ){ name = doc.object().value("name").toString(); }
|
||||
if(doc.object().contains("id") ){ id = doc.object().value("id").toString(); }
|
||||
if(doc.object().contains("args") ){ args = doc.object().value("args"); }
|
||||
else{
|
||||
//no args structure - treat the entire body as the arguments struct
|
||||
args = doc.object();
|
||||
}
|
||||
}
|
||||
}
|
||||
//Now do any REST -> JSON conversions if necessary
|
||||
if(!URI.isEmpty()){
|
||||
//TO-DO
|
||||
name = URI.section("/",-1); //last entry
|
||||
namesp = URI.section("/",1,1); //URI excluding name
|
||||
}
|
||||
}
|
||||
~RestInputStruct(){}
|
||||
RestInputStruct(QString message = "", bool isRest = false);
|
||||
~RestInputStruct();
|
||||
|
||||
void ParseBodyIntoJson();
|
||||
|
||||
};
|
||||
|
||||
class RestOutputStruct{
|
||||
@@ -98,110 +51,7 @@ public:
|
||||
}
|
||||
~RestOutputStruct(){}
|
||||
|
||||
QString assembleMessage(){
|
||||
if( !in_struct.VERB.isEmpty() ){
|
||||
//REST output syntax
|
||||
QStringList headers;
|
||||
QString firstline = in_struct.HTTPVERSION.simplified();
|
||||
if(firstline.isEmpty()){ firstline = CurHttpVersion.simplified(); }//default value
|
||||
QString Body;
|
||||
if(!out_args.isNull()){
|
||||
QJsonObject obj; obj.insert("args", out_args);
|
||||
Body = QJsonDocument(obj).toJson();
|
||||
}
|
||||
switch(CODE){
|
||||
case PROCESSING:
|
||||
firstline.append(" 102 Processing"); break;
|
||||
case OK:
|
||||
firstline.append(" 200 OK"); break;
|
||||
case CREATED:
|
||||
firstline.append(" 201 Created"); break;
|
||||
case ACCEPTED:
|
||||
firstline.append(" 202 Accepted"); break;
|
||||
case NOCONTENT:
|
||||
firstline.append(" 204 No Content"); break;
|
||||
case RESETCONTENT:
|
||||
firstline.append(" 205 Reset Content"); break;
|
||||
case PARTIALCONTENT:
|
||||
firstline.append(" 206 Partial Content"); break;
|
||||
case BADREQUEST:
|
||||
firstline.append(" 400 Bad Request"); break;
|
||||
case UNAUTHORIZED:
|
||||
firstline.append(" 401 Unauthorized"); break;
|
||||
case FORBIDDEN:
|
||||
firstline.append(" 403 Forbidden"); break;
|
||||
case NOTFOUND:
|
||||
firstline.append(" 404 Not Found"); break;
|
||||
}
|
||||
headers << firstline;
|
||||
headers << "Server: SysAdm/1.0";
|
||||
headers << "Date: "+QDateTime::currentDateTime().toString(Qt::ISODate).simplified();
|
||||
if(!Header.isEmpty()) {
|
||||
for (int i = 0; i < Header.size(); ++i)
|
||||
headers << Header.at(i).simplified();
|
||||
}
|
||||
//Now add the body of the return
|
||||
if(!Body.isEmpty()){ headers << "Content-Length: "+QString::number(Body.toUtf8().size()); } //number of bytes for the body
|
||||
headers << "";
|
||||
headers << Body;
|
||||
return headers.join("\r\n");
|
||||
|
||||
}else{
|
||||
//JSON output (load all the input fields for the moment)
|
||||
QString oname = "response"; //use this for valid responses (input ID found)
|
||||
if(in_struct.id.isEmpty()){ oname = in_struct.name; }
|
||||
QString onamesp = in_struct.namesp;
|
||||
QString oid = in_struct.id;
|
||||
if(CODE!=OK){
|
||||
//Format the output based on the type of error
|
||||
QJsonObject out_err;
|
||||
switch(CODE){
|
||||
case PROCESSING:
|
||||
//oname = onamesp = "error";
|
||||
out_err.insert("code","102"); out_err.insert("message", "Processing"); break;
|
||||
case CREATED:
|
||||
//oname = onamesp = "error";
|
||||
out_err.insert("code","201"); out_err.insert("message", "Created"); break;
|
||||
case ACCEPTED:
|
||||
//oname = onamesp = "error";
|
||||
out_err.insert("code","202"); out_err.insert("message", "Accepted"); break;
|
||||
case NOCONTENT:
|
||||
oname = onamesp = "error";
|
||||
out_err.insert("code","204"); out_err.insert("message", "No Content"); break;
|
||||
case RESETCONTENT:
|
||||
//oname = onamesp = "error";
|
||||
out_err.insert("code","205"); out_err.insert("message", "Reset Content"); break;
|
||||
case PARTIALCONTENT:
|
||||
oname = onamesp = "error";
|
||||
out_err.insert("code","206"); out_err.insert("message", "Partial Content"); break;
|
||||
case BADREQUEST:
|
||||
oname = onamesp = "error";
|
||||
out_err.insert("code","400"); out_err.insert("message", "Bad Request"); break;
|
||||
case UNAUTHORIZED:
|
||||
oname = onamesp = "error";
|
||||
out_err.insert("code","401"); out_err.insert("message", "Unauthorized"); break;
|
||||
case FORBIDDEN:
|
||||
oname = onamesp = "error";
|
||||
out_err.insert("code","403"); out_err.insert("message", "Forbidden"); break;
|
||||
case NOTFOUND:
|
||||
oname = onamesp = "error";
|
||||
out_err.insert("code","404"); out_err.insert("message", "Not Found"); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
out_args = out_err;
|
||||
}
|
||||
//Now assemple the JSON output
|
||||
QJsonObject obj;
|
||||
obj.insert("namespace",onamesp);
|
||||
obj.insert("name",oname);
|
||||
obj.insert("id",oid);
|
||||
obj.insert("args", out_args);
|
||||
//Convert the JSON to string form
|
||||
QJsonDocument doc(obj);
|
||||
return doc.toJson(QJsonDocument::Compact);
|
||||
}
|
||||
}
|
||||
QString assembleMessage(); //normal operation - no special processing needed
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -90,9 +90,12 @@ void WebSocket::sendReply(QString msg){
|
||||
|
||||
void WebSocket::EvaluateREST(QString msg){
|
||||
//Parse the message into it's elements and proceed to the main data evaluation
|
||||
RestInputStruct IN(msg);
|
||||
//NOTE: All the REST functionality is disabled for the moment, until we decide to turn it on again at a later time (just need websockets right now - not full REST)
|
||||
|
||||
RestInputStruct IN(msg, TSOCKET!=0);
|
||||
if(SOCKET!=0 && !IN.Header.isEmpty()){
|
||||
//Bridge-relay message - need to decrypt the message body before it can be parsed
|
||||
//IN.Body = AUTHSYSTEM->decryptString(IN.Body, key); //TO-DO
|
||||
IN.ParseBodyIntoJson();
|
||||
}
|
||||
if(DEBUG){
|
||||
qDebug() << "New REST Message:";
|
||||
qDebug() << " VERB:" << IN.VERB << "URI:" << IN.URI;
|
||||
@@ -120,7 +123,6 @@ void WebSocket::EvaluateREST(QString msg){
|
||||
out.Header << "Content-Type: text/json; charset=utf-8";
|
||||
this->sendReply(out.assembleMessage());
|
||||
}else{
|
||||
//EvaluateRequest(IN);
|
||||
if(IN.name.startsWith("auth") || (IN.namesp.toLower()=="rpc" && IN.name.toLower()=="identify") ){
|
||||
//Keep auth/pre-auth system requests in order
|
||||
EvaluateRequest(IN);
|
||||
@@ -278,12 +280,19 @@ if(out.in_struct.namesp.toLower() == "rpc"){
|
||||
}
|
||||
}
|
||||
//Return any information
|
||||
|
||||
QString msg = out.assembleMessage();
|
||||
if(SOCKET!=0 && !REQ.Header.isEmpty()){
|
||||
//BRIDGE RELAY - alternate format
|
||||
//Need to encrypt the message for output (TO-DO)
|
||||
//msg = AUTHSYSTEM->encryptString(msg, key);
|
||||
//Now add the destination ID
|
||||
msg.prepend( REQ.Header.join("\n")+"\n");
|
||||
}
|
||||
if(out.CODE == RestOutputStruct::FORBIDDEN && SOCKET!=0 && SOCKET->isValid()){
|
||||
this->sendReply(out.assembleMessage());
|
||||
this->sendReply(msg);
|
||||
SOCKET->close(QWebSocketProtocol::CloseCodeNormal, "Too Many Authorization Failures - Try again later");
|
||||
}else{
|
||||
this->emit SendMessage(out.assembleMessage());
|
||||
this->emit SendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ private:
|
||||
void ParseIncoming();
|
||||
|
||||
//Main connection comminucations procedure
|
||||
void EvaluateREST(QString); //Text -> Rest/JSON struct
|
||||
void EvaluateRequest(const RestInputStruct&); // Parse Rest/JSON (does auth/events)
|
||||
void EvaluateREST(QString); //STAGE 1 response: Text -> Rest/JSON struct
|
||||
void EvaluateRequest(const RestInputStruct&); //STAGE 2 response: Parse Rest/JSON (does auth/events)
|
||||
|
||||
//Simplification functions
|
||||
QString JsonValueToString(QJsonValue);
|
||||
@@ -82,9 +82,9 @@ private slots:
|
||||
void SocketClosing();
|
||||
|
||||
//Currently connected socket signal/slot connections
|
||||
void EvaluateMessage(const QByteArray&);
|
||||
void EvaluateMessage(const QString&);
|
||||
void EvaluateTcpMessage();
|
||||
void EvaluateMessage(const QByteArray&); //initial message input (raw bytes - WebSocket)
|
||||
void EvaluateMessage(const QString&); //initial message input (text - WebSocket)
|
||||
void EvaluateTcpMessage(); //initial message input (text - REST)
|
||||
|
||||
//SSL signal handling
|
||||
void nowEncrypted(); //the socket/connection is now encrypted
|
||||
|
||||
@@ -7,7 +7,6 @@ QT = core network websockets concurrent sql
|
||||
HEADERS += globals.h globals-qt.h \
|
||||
WebServer.h \
|
||||
WebSocket.h \
|
||||
# syscache-client.h \
|
||||
RestStructs.h \
|
||||
AuthorizationManager.h \
|
||||
SslServer.h \
|
||||
@@ -18,9 +17,9 @@ HEADERS += globals.h globals-qt.h \
|
||||
SOURCES += main.cpp \
|
||||
WebServer.cpp \
|
||||
WebSocket.cpp \
|
||||
RestStructs.cpp \
|
||||
WebBackend.cpp \
|
||||
WebBackendSlots.cpp \
|
||||
# syscache-client.cpp \
|
||||
AuthorizationManager.cpp \
|
||||
EventWatcher.cpp \
|
||||
LogManager.cpp \
|
||||
|
||||
Reference in New Issue
Block a user