Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhanced the routes and apikeys table #1998

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
2 changes: 2 additions & 0 deletions manual/src/main/paradox/how-to-s/wasmo-installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ Let's edit the fake input context by adding the exepected foo Header.
},
"cookies"
...
}
}
```

Resubmit the command. It should pass.
Expand Down
186 changes: 99 additions & 87 deletions otoroshi/app/api/api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1031,89 +1031,87 @@ class GenericApiController(ApiAction: ApiAction, cc: ControllerComponents)(impli
)
.getOrElse(Seq.empty[(String, String)])
val hasFilters = filters.nonEmpty
if (hasFilters) {
val reducedItems = if (hasFilters) {
val items: Seq[JsValue] = arr.value.filter { elem =>
filters.forall {
case (key, value) if key.startsWith("$") && key.contains(".") => {
elem.atPath(key).as[JsValue] match {
case JsString(v) => v == value
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case _ => false
}

val reducedItems = if (hasFilters) {
val items: Seq[JsValue] = arr.value.filter { elem =>
filters.forall {
case (key, value) if key.startsWith("$") && key.contains(".") => {
elem.atPath(key).as[JsValue] match {
case JsString(v) => v == value
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case _ => false
}
case (key, value) if key.contains(".") => {
elem.at(key).as[JsValue] match {
case JsString(v) => v == value
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case _ => false
}
}
case (key, value) if key.contains(".") => {
elem.at(key).as[JsValue] match {
case JsString(v) => v == value
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case _ => false
}
case (key, value) if key.contains("/") => {
elem.atPointer(key).as[JsValue] match {
case JsString(v) => v == value
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case _ => false
}
}
case (key, value) if key.contains("/") => {
elem.atPointer(key).as[JsValue] match {
case JsString(v) => v == value
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case _ => false
}
case (key, value) => {
(elem \ key).as[JsValue] match {
case JsString(v) => v == value
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case _ => false
}
}
case (key, value) => {
(elem \ key).as[JsValue] match {
case JsString(v) => v == value
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case _ => false
}
}
}
items
} else {
arr.value
}
val filteredItems = if (filtered.nonEmpty) {
val items: Seq[JsValue] = reducedItems.filter { elem =>
filtered.forall { case (key, value) =>
JsonOperationsHelper.getValueAtPath(key.toLowerCase(), elem)._2.asOpt[JsValue] match {
case Some(v) =>
v match {
case JsString(v) => v.toLowerCase().indexOf(value) != -1
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case JsObject(v) if v.isEmpty =>
JsonOperationsHelper.getValueAtPath(key, elem)._2.asOpt[JsValue] match {
case Some(v) =>
v match {
case JsString(v) => v.toLowerCase().indexOf(value) != -1
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case _ => false
}
case _ => false
}
case _ => false
}
case _ =>
false
}
items
} else {
arr.value
}

val filteredItems = if (filtered.nonEmpty) {
val items: Seq[JsValue] = reducedItems.filter { elem =>
filtered.forall { case (key, value) =>
JsonOperationsHelper.getValueAtPath(key.toLowerCase(), elem)._2.asOpt[JsValue] match {
case Some(v) =>
v match {
case JsString(v) => v.toLowerCase().indexOf(value) != -1
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case JsObject(v) if v.isEmpty =>
JsonOperationsHelper.getValueAtPath(key, elem)._2.asOpt[JsValue] match {
case Some(v) =>
v match {
case JsString(v) => v.toLowerCase().indexOf(value) != -1
case JsBoolean(v) => v == value.toBoolean
case JsNumber(v) => v.toDouble == value.toDouble
case JsArray(values) => values.contains(JsString(value))
case _ => false
}
case _ => false
}
case _ => false
}
case _ =>
false
}
}
items
} else {
reducedItems
}
JsArray(filteredItems).some
items
} else {
arr.some
reducedItems
}
JsArray(filteredItems).some
}
case _ => _entity.some
}
Expand All @@ -1138,9 +1136,9 @@ class GenericApiController(ApiAction: ApiAction, cc: ControllerComponents)(impli
JsArray(sorted.foldLeft(arr.value) {
case (sortedArray, sort) => {
val out = sortedArray
.sortBy { r =>
String.valueOf(JsonOperationsHelper.getValueAtPath(sort._1.toLowerCase(), r)._2)
.sortBy { r => String.valueOf(JsonOperationsHelper.getValueAtPath(sort._1.toLowerCase(), r)._2)
}(Ordering[String].reverse)

if (sort._2) {
out.reverse
} else {
Expand All @@ -1156,7 +1154,9 @@ class GenericApiController(ApiAction: ApiAction, cc: ControllerComponents)(impli
}
}

private def paginateEntity(_entity: JsValue, request: RequestHeader): Option[JsValue] = {
case class PaginatedContent(pages: Int = -1, content: JsValue)

private def paginateEntity(_entity: JsValue, request: RequestHeader): Option[PaginatedContent] = {
_entity match {
case arr @ JsArray(_) => {
val paginationPage: Int =
Expand All @@ -1172,24 +1172,32 @@ class GenericApiController(ApiAction: ApiAction, cc: ControllerComponents)(impli
.map(_.toInt)
.getOrElse(Int.MaxValue)
val paginationPosition = (paginationPage - 1) * paginationPageSize
JsArray(arr.value.slice(paginationPosition, paginationPosition + paginationPageSize)).some

val content = arr.value.slice(paginationPosition, paginationPosition + paginationPageSize)
PaginatedContent(
pages = Math.ceil(arr.value.size.toFloat / paginationPageSize).toInt,
content = JsArray(content)
).some
}
case _ => _entity.some
case _ => PaginatedContent(
content = _entity
).some
}
}

private def projectedEntity(_entity: JsValue, request: RequestHeader): Option[JsValue] = {
private def projectedEntity(_entity: PaginatedContent, request: RequestHeader): Option[PaginatedContent] = {
val fields = request.getQueryString("fields").map(_.split(",").toSeq).getOrElse(Seq.empty[String])
val hasFields = fields.nonEmpty
if (hasFields) {
_entity match {
val content = _entity.content match {
case arr @ JsArray(_) =>
JsArray(arr.value.map { item =>
JsonOperationsHelper.filterJson(item.asObject, fields)
}).some
case obj @ JsObject(_) => JsonOperationsHelper.filterJson(obj, fields).some
case _ => _entity.some
})
case obj @ JsObject(_) => JsonOperationsHelper.filterJson(obj, fields)
case _ => return _entity.some
}
_entity.copy(content = content).some
} else {
_entity.some
}
Expand All @@ -1210,9 +1218,9 @@ class GenericApiController(ApiAction: ApiAction, cc: ControllerComponents)(impli
projected <- projectedEntity(paginated, request)
} yield projected).get
} else {
_entity
PaginatedContent(content = _entity)
}
entity match {
entity.content match {
case JsArray(seq) if !request.accepts("application/json") && request.accepts("application/x-ndjson") => {
res
.sendEntity(
Expand All @@ -1222,6 +1230,7 @@ class GenericApiController(ApiAction: ApiAction, cc: ControllerComponents)(impli
contentType = "application/x-ndjson".some
)
)
.withHeaders("X-Pages" -> entity.pages.toString)
.applyOnIf(addHeaders.nonEmpty) { r =>
r.withHeaders(addHeaders.toSeq: _*)
}
Expand All @@ -1232,8 +1241,9 @@ class GenericApiController(ApiAction: ApiAction, cc: ControllerComponents)(impli
case _
if !request.accepts("application/json") && (request
.accepts("application/yaml") || request.accepts("application/yml")) =>
res(Yaml.write(entity))
res(Yaml.write(entity.content))
.as("application/yaml")
.withHeaders("X-Pages" -> entity.pages.toString)
.applyOnIf(addHeaders.nonEmpty) { r =>
r.withHeaders(addHeaders.toSeq: _*)
}
Expand All @@ -1249,21 +1259,23 @@ class GenericApiController(ApiAction: ApiAction, cc: ControllerComponents)(impli
"apiVersion" -> "proxy.otoroshi.io/v1",
"kind" -> resEntity.get.kind,
"metadata" -> Json.obj(
"name" -> entity.select("name").asOpt[String].getOrElse("no name").asInstanceOf[String]
"name" -> entity.content.select("name").asOpt[String].getOrElse("no name").asInstanceOf[String]
),
"spec" -> entity
"spec" -> entity.content
)
)
)
.as("application/yaml")
.withHeaders("X-Pages" -> entity.pages.toString)
.applyOnIf(addHeaders.nonEmpty) { r =>
r.withHeaders(addHeaders.toSeq: _*)
}
.applyOnIf(resEntity.nonEmpty && resEntity.get.version.deprecated) { r =>
r.withHeaders("Otoroshi-Api-Deprecated" -> "yes")
}
case _ =>
res(entity)
res(entity.content)
.withHeaders("X-Pages" -> entity.pages.toString)
.applyOnIf(addHeaders.nonEmpty) { r =>
r.withHeaders(addHeaders.toSeq: _*)
}
Expand Down
1 change: 0 additions & 1 deletion otoroshi/app/models/JWTVerifier.scala
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,6 @@ case class JWKSAlgoSettings(
}

override def asAlgorithmF(mode: AlgoMode)(implicit env: Env, ec: ExecutionContext): Future[Option[Algorithm]] = {

mode match {
case InputMode(alg, Some(kid)) => {
JWKSAlgoSettings.cache.getIfPresent(url) match {
Expand Down
1 change: 1 addition & 0 deletions otoroshi/app/next/plugins/otoroshi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ class OtoroshiInfos extends NgRequestTransformer {
val config = ctx
.cachedConfigFn(internalName)(json => NgOtoroshiInfoConfig(json).some)
.getOrElse(NgOtoroshiInfoConfig(ctx.config))

var claim = InfoTokenHelper.generateInfoToken(
ctx.route.name,
config.secComVersion,
Expand Down
1 change: 1 addition & 0 deletions otoroshi/app/plugins/jobs/kubernetes/crds.scala
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ class ClientSupport(val client: KubernetesClient, logger: Logger)(implicit ec: E
val template =
if (useDefaultTemplate) getDefaultTemplate(templateName, _spec)
else (client.config.templates \ templateName).asOpt[JsObject].getOrElse(Json.obj())

val spec = if (client.config.crdsOverride) {
template.deepMerge(_spec.as[JsObject])
} else {
Expand Down
Loading
Loading