Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 33 additions & 13 deletions App/Server/RESTAPIRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,20 @@ void RESTAPIRegistry::registerRESTAPI(
if (!FoundDoc)
throw exRESTRegistry("Seems that you have not use API macro to define your API: " + MethodName);

#ifdef QT_DEBUG
QString __MethodKey = "/" + _module->moduleBaseName().replace(":", "/") + '/' + _method.name();
__MethodKey = __MethodKey.replace(QRegularExpression("//+"), "/");
if (__MethodKey == "/Account/User/apiUPDATEextraInfo") {
int ii; ii = 0;
}
#endif

constexpr char COMMA_SIGN[] = "$_COMMA_$";

MethodSignature = MethodSignature.trimmed().replace("','", QString("'%1'").arg(COMMA_SIGN));
bool DQuoteStarted = false, BackslashFound = false;
bool DQuoteStarted = false,
BackslashFound = false,
InTemplateParameters = false;
QString CommaReplacedMethodSignature;

for (int i=0; i< MethodSignature.size(); ++i) {
Expand All @@ -235,16 +245,29 @@ void RESTAPIRegistry::registerRESTAPI(
else if (MethodSignature.at(i).toLatin1() == '\\') {
BackslashFound = true;
} else if (MethodSignature.at(i).toLatin1() == '"') {
CommaReplacedMethodSignature += '"';
CommaReplacedMethodSignature += MethodSignature.at(i);
if (BackslashFound)
BackslashFound = false;
else
DQuoteStarted = false;
} else
CommaReplacedMethodSignature += MethodSignature.at(i);

} else if (InTemplateParameters) {
if (MethodSignature.at(i).toLatin1() == ',')
CommaReplacedMethodSignature += COMMA_SIGN;
else if (MethodSignature.at(i).toLatin1() == '>') {
CommaReplacedMethodSignature += MethodSignature.at(i);
InTemplateParameters = false;
} else
CommaReplacedMethodSignature += MethodSignature.at(i);

} else if (MethodSignature.at(i).toLatin1() == '"') {
CommaReplacedMethodSignature += '"';
CommaReplacedMethodSignature += MethodSignature.at(i);
DQuoteStarted = true;
} else if (MethodSignature.at(i).toLatin1() == '<') {
CommaReplacedMethodSignature += MethodSignature.at(i);
InTemplateParameters = true;
} else
CommaReplacedMethodSignature += MethodSignature.at(i);
}
Expand All @@ -254,14 +277,6 @@ void RESTAPIRegistry::registerRESTAPI(
QList<QByteArray> parameterTypes = _method.parameterTypes();
auto ParamsParts = CommaReplacedMethodSignature.split(',');

#ifdef QT_DEBUG
QString MethodKey = "/" + _module->moduleBaseName().replace(":", "/") + '/' + _method.name();
MethodKey = MethodKey.replace(QRegularExpression("//+"), "/");
if (MethodKey == "/Account/OfflinePayments/apiGET") {
int ii; ii = 0;
}
#endif

for (quint8 ParamIndex=0; ParamIndex<ParamsParts.length(); ParamIndex++) {
QString Param = ParamsParts[ParamIndex];

Expand Down Expand Up @@ -306,7 +321,9 @@ void RESTAPIRegistry::registerRESTAPI(
else
DefaultValues.append(Value);
} else if (ArgSpecs->isNullable())
throw exRESTRegistry("Nullable parameter: <"+_method.parameterNames().value(ParamIndex)+"> on method: <" + MethodName + "> must have default value" );
throw exRESTRegistry(QString("Nullable parameter: <%1> on method: <%2> must have default value" )
.arg(*_method.parameterNames().value(ParamIndex))
.arg(MethodName));
else
DefaultValues.append(QVariant());
}
Expand Down Expand Up @@ -689,7 +706,10 @@ void RESTAPIRegistry::dumpAPIs()
QString JWTType = "";
// if (API.APIObject->requiresJWT())
if (API.APIObject->tokenActorType() != enuTokenActorType::ANONYMOUSE)
JWTType = QString(" (JWT:%1)").arg(enuTokenActorType::toStr(API.APIObject->tokenActorType()));
JWTType = QString(" (JWT:%1%2)")
.arg(enuTokenActorType::toStr(API.APIObject->tokenActorType()))
.arg(API.APIObject->tokenIsOptional() ? "/OPTIONAL" : "")
;

TargomanDebug(5).noLabel().noquote().nospace()
<< (IsLastAPI ? " " : "│") << " "
Expand Down
12 changes: 6 additions & 6 deletions App/Server/StaticModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ StaticModule::StaticModule() :
{ ; }

TAPI::RawData_t IMPL_REST_GET_OR_POST(StaticModule, openAPI_json, (
APICALLBOOM_TYPE_NO_JWT_IMPL &APICALLBOOM_PARAM
APICALLBOOM_TYPE_JWT_ANONYMOUSE_IMPL &APICALLBOOM_PARAM
)) {
gServerStats.Success.inc();

Expand All @@ -49,15 +49,15 @@ TAPI::RawData_t IMPL_REST_GET_OR_POST(StaticModule, openAPI_json, (
}

QVariant IMPL_REST_GET_OR_POST(StaticModule, openAPI_yaml, (
APICALLBOOM_TYPE_NO_JWT_IMPL &APICALLBOOM_PARAM
APICALLBOOM_TYPE_JWT_ANONYMOUSE_IMPL &APICALLBOOM_PARAM
)) {
throw exHTTPMethodNotAllowed("Yaml openAPI is not implemented yet");
}

//TAPI::ResponseRedirect_t
//TAPI::FileData_t
QVariant IMPL_REST_GET_OR_POST(StaticModule, swaggerui, (
APICALLBOOM_TYPE_NO_JWT_IMPL &APICALLBOOM_PARAM
APICALLBOOM_TYPE_JWT_ANONYMOUSE_IMPL &APICALLBOOM_PARAM
)) {
if (ServerCommonConfigs::SwaggerUI.value().isEmpty())
throw exHTTPNotFound("Swagger is not configured");
Expand All @@ -76,7 +76,7 @@ QVariant IMPL_REST_GET_OR_POST(StaticModule, swaggerui, (
}

QVariant IMPL_REST_GET_OR_POST(StaticModule, stats_json, (
APICALLBOOM_TYPE_NO_JWT_IMPL &APICALLBOOM_PARAM,
APICALLBOOM_TYPE_JWT_ANONYMOUSE_IMPL &APICALLBOOM_PARAM,
bool _full
)) {
gServerStats.Success.inc();
Expand All @@ -85,7 +85,7 @@ QVariant IMPL_REST_GET_OR_POST(StaticModule, stats_json, (
}

QVariant IMPL_REST_GET_OR_POST(StaticModule, version, (
APICALLBOOM_TYPE_NO_JWT_IMPL &APICALLBOOM_PARAM
APICALLBOOM_TYPE_JWT_ANONYMOUSE_IMPL &APICALLBOOM_PARAM
)) {
gServerStats.Success.inc();

Expand All @@ -101,7 +101,7 @@ QVariant IMPL_REST_GET_OR_POST(StaticModule, version, (
}

QVariant IMPL_REST_GET_OR_POST(StaticModule, ping, (
APICALLBOOM_TYPE_NO_JWT_IMPL &APICALLBOOM_PARAM
APICALLBOOM_TYPE_JWT_ANONYMOUSE_IMPL &APICALLBOOM_PARAM
)) {
gServerStats.Success.inc();

Expand Down
12 changes: 6 additions & 6 deletions App/Server/StaticModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private slots:
TAPI::RawData_t EXREST_GET_OR_POST(
openAPI_json,
(
APICALLBOOM_TYPE_NO_JWT_DECL &APICALLBOOM_PARAM
APICALLBOOM_TYPE_JWT_ANONYMOUSE_DECL &APICALLBOOM_PARAM
),
"",
{
Expand All @@ -55,7 +55,7 @@ private slots:
QVariant EXREST_GET_OR_POST(
openAPI_yaml,
(
APICALLBOOM_TYPE_NO_JWT_DECL &APICALLBOOM_PARAM
APICALLBOOM_TYPE_JWT_ANONYMOUSE_DECL &APICALLBOOM_PARAM
),
"",
{
Expand All @@ -69,7 +69,7 @@ private slots:
QVariant EXREST_GET_OR_POST(
swaggerui,
(
APICALLBOOM_TYPE_NO_JWT_DECL &APICALLBOOM_PARAM
APICALLBOOM_TYPE_JWT_ANONYMOUSE_DECL &APICALLBOOM_PARAM
),
"",
{
Expand All @@ -80,7 +80,7 @@ private slots:
QVariant EXREST_GET_OR_POST(
stats_json,
(
APICALLBOOM_TYPE_NO_JWT_DECL &APICALLBOOM_PARAM,
APICALLBOOM_TYPE_JWT_ANONYMOUSE_DECL &APICALLBOOM_PARAM,
bool _full = false
),
"",
Expand All @@ -93,7 +93,7 @@ private slots:
QVariant EXREST_GET_OR_POST(
version,
(
APICALLBOOM_TYPE_NO_JWT_DECL &APICALLBOOM_PARAM
APICALLBOOM_TYPE_JWT_ANONYMOUSE_DECL &APICALLBOOM_PARAM
),
"",
{
Expand All @@ -104,7 +104,7 @@ private slots:
QVariant EXREST_GET_OR_POST(
ping,
(
APICALLBOOM_TYPE_NO_JWT_DECL &APICALLBOOM_PARAM
APICALLBOOM_TYPE_JWT_ANONYMOUSE_DECL &APICALLBOOM_PARAM
),
"",
{
Expand Down
21 changes: 16 additions & 5 deletions App/Server/clsAPIObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ clsAPIObject::clsAPIObject(
HasExtraMethodName(_hasExtraMethodName),
Parent(_module),
// RequiresJWT(false)
TokenActorType(enuTokenActorType::ANONYMOUSE)
TokenActorType(enuTokenActorType::ANONYMOUSE),
TokenIsOptional(true)
{
QList<QByteArray> parameterTypes = _method.parameterTypes();
quint8 i = 0;
Expand All @@ -69,14 +70,24 @@ clsAPIObject::clsAPIObject(
this->ParamTypesName.append(PARAM_JWT);
this->ParamTypesID.append(QMetaType::type(PARAM_JWT));
this->BaseMethod.DefaultValues[0] = {};
} else */if (ParameterTypeName.startsWith(APICALLBOOM_TYPE_BASE_STR)) { //APICALLBOOM_TYPE_NO_JWT_DECL)) {
} else */if (ParameterTypeName.startsWith(APICALLBOOM_TYPE_BASE_STR)) { //APICALLBOOM_TYPE_JWT_ANONYMOUSE_DECL)) {
--this->RequiredParamsCount;
this->BaseMethod.DefaultValues.removeAt(0);
// this->RequiresJWT = true;
if (ParameterTypeName.startsWith(APICALLBOOM_TYPE_JWT_USER_DECL_STR))

if (ParameterTypeName.startsWith(APICALLBOOM_TYPE_JWT_USER_DECL_STR)) {
this->TokenActorType = enuTokenActorType::USER;
this->TokenIsOptional = false;
} else if (ParameterTypeName.startsWith(APICALLBOOM_TYPE_JWT_USER_OR_ANONYMOUSE_DECL_STR)) {
this->TokenActorType = enuTokenActorType::USER;
else if (ParameterTypeName.startsWith(APICALLBOOM_TYPE_JWT_API_DECL_STR))
this->TokenIsOptional = true;
} else if (ParameterTypeName.startsWith(APICALLBOOM_TYPE_JWT_API_DECL_STR)) {
this->TokenActorType = enuTokenActorType::API;
this->TokenIsOptional = false;
} else if (ParameterTypeName.startsWith(APICALLBOOM_TYPE_JWT_API_OR_ANONYMOUSE_DECL_STR)) {
this->TokenActorType = enuTokenActorType::API;
this->TokenIsOptional = true;
}

} else {
QByteArray ParamNameNoUnderScore = (ParamName.startsWith('_') ? ParamName.mid(1) : ParamName);
this->ParamNames.append(ParamNameNoUnderScore);
Expand Down
2 changes: 2 additions & 0 deletions App/Server/clsAPIObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class clsAPIObject : public intfAPIObject, public QObject
// return this->Parent->actorType();
// }
enuTokenActorType::Type tokenActorType() { return this->TokenActorType; }
bool tokenIsOptional() { return this->TokenIsOptional; }

// inline bool requiresCookies() const {
// return this->ParamTypesName.contains(PARAM_COOKIES);
Expand Down Expand Up @@ -165,6 +166,7 @@ class clsAPIObject : public intfAPIObject, public QObject
intfPureModule* Parent;
// bool RequiresJWT;
enuTokenActorType::Type TokenActorType;
bool TokenIsOptional;

friend class RESTAPIRegistry;
friend class OpenAPIGenerator;
Expand Down
64 changes: 38 additions & 26 deletions App/Server/clsRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,20 +335,25 @@ clsRequestHandler::stuResult clsRequestHandler::run(
const QString& _pksByPath,
const QString& _api
) {
// QVariantMap ResponseHeaders;

auto fnTiming = [=](const QString &_name, const QString &_desc, quint64 _nanoSecs) {
this->addToTimings(_name, _desc, _nanoSecs);
};

enuTokenActorType::Type TokenActorType = _apiObject->tokenActorType();
QScopedPointer<intfAPICallBoom> APICALLBOOM;
// if (_apiObject->requiresJWT())
if (_apiObject->tokenActorType() == enuTokenActorType::USER)
APICALLBOOM.reset(new APICALLBOOM_TYPE_JWT_USER_DECL(fnTiming));
else if (_apiObject->tokenActorType() == enuTokenActorType::API)
APICALLBOOM.reset(new APICALLBOOM_TYPE_JWT_API_DECL(fnTiming));
else //enuTokenActorType::ANONYMOUSE
APICALLBOOM.reset(new APICALLBOOM_TYPE_NO_JWT_DECL(fnTiming));

if (TokenActorType == enuTokenActorType::USER) {
if (_apiObject->tokenIsOptional())
APICALLBOOM.reset(new APICALLBOOM_TYPE_JWT_USER_OR_ANONYMOUSE_DECL(fnTiming));
else
APICALLBOOM.reset(new APICALLBOOM_TYPE_JWT_USER_DECL(fnTiming));
} else if (TokenActorType == enuTokenActorType::API) {
if (_apiObject->tokenIsOptional())
APICALLBOOM.reset(new APICALLBOOM_TYPE_JWT_API_OR_ANONYMOUSE_DECL(fnTiming));
else
APICALLBOOM.reset(new APICALLBOOM_TYPE_JWT_API_DECL(fnTiming));
} else //enuTokenActorType::ANONYMOUSE
APICALLBOOM.reset(new APICALLBOOM_TYPE_JWT_ANONYMOUSE_DECL(fnTiming));

try {
for (auto QueryIter = _queries.begin(); QueryIter != _queries.end(); ++QueryIter)
Expand All @@ -360,19 +365,30 @@ clsRequestHandler::stuResult clsRequestHandler::run(
QString RemoteIP = this->toIPv4(this->Request->remoteAddress());
qhttp::THeaderHash Headers = this->Request->headers();
qhttp::THeaderHash Cookies;
TAPI::JWT_t JWT;

// enuTokenActorType::Type AcceptableActorType = _apiObject->moduleActorType();
enuTokenActorType::Type TokenActorType = _apiObject->tokenActorType();
// if (_apiObject->requiresJWT()) {
if (TokenActorType != enuTokenActorType::ANONYMOUSE) {
auto ServerTiming = APICALLBOOM->createScopeTiming("jwt");
//JWT
TAPI::JWT_t JWT;
{
auto JWTServerTiming = APICALLBOOM->createScopeTiming("jwt");

QString BearerToken;
QString Auth = Headers.value("authorization");
if (Auth.startsWith("Bearer ")) {
QString BearerToken = Auth.mid(sizeof("Bearer"));
BearerToken = Auth.mid(sizeof("Bearer")).trimmed();
Headers.remove("authorization");
}

if (BearerToken.isEmpty()) {
if ((TokenActorType != enuTokenActorType::ANONYMOUSE)
&& (_apiObject->tokenIsOptional() == false))
throw exHTTPForbidden("No authentication header is present");

} else if (TokenActorType == enuTokenActorType::ANONYMOUSE) {
// throw exHTTPForbidden("The authentication header should not be sent for anonymouse apis");
APICALLBOOM->addResponseHeader("x-tapi-jwt-warning", "no jwt needed");
APICALLBOOM->addResponseHeaderNameToExpose("x-tapi-jwt-warning");

} else {
try {
QJWT::verifyJWT(
BearerToken,
Expand All @@ -398,10 +414,8 @@ clsRequestHandler::stuResult clsRequestHandler::run(
if (JWT.contains("typ"))
TokenType = enuTokenActorType::toEnum(JWT["typ"].toString());

/*if (TokenType == enuTokenActorType::System) {
//do nothing
} else*/ if (TokenType == enuTokenActorType::USER) {
auto ServerTiming = APICALLBOOM->createScopeTiming("jwt", "renew");
if (TokenType == enuTokenActorType::USER) {
auto RenewJWTServerTiming = APICALLBOOM->createScopeTiming("jwt", "renew");

bool IsRenewed = false;
QString NewToken = Authentication::renewExpiredJWT(
Expand All @@ -423,15 +437,13 @@ clsRequestHandler::stuResult clsRequestHandler::run(
throw exHTTPForbidden("API token is expired");
else
throw exHTTPForbidden(QString("Unknown token type `%1`").arg(TokenType));
}
} //catch (exJWTExpired &exp)

JWT["encodedJWT"] = BearerToken;
} else
throw exHTTPForbidden("No valid authentication header is present");

// APICALLBOOM->setJWT(JWT);
} // if (_apiObject->requiresJWT())
} // if (BearerToken.isEmpty() == false) {
} //jwt scope

//--
if (/*_apiObject->requiresCookies() && */Headers.value("cookie").size()) {
foreach (auto Cookie, Headers.value("cookie").split(';')) {
auto CookieParts = Cookie.split('=');
Expand Down
Loading