mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 02:18:26 +00:00
Make internal endpoints available to nodes only
This commit is contained in:
@ -18,6 +18,7 @@ import docspell.extract.ExtractConfig
|
||||
import docspell.ftssolr.SolrConfig
|
||||
import docspell.joex.analysis.RegexNerFile
|
||||
import docspell.joex.hk.HouseKeepingConfig
|
||||
import docspell.joex.routes.InternalHeader
|
||||
import docspell.joex.scheduler.{PeriodicSchedulerConfig, SchedulerConfig}
|
||||
import docspell.joex.updatecheck.UpdateCheckConfig
|
||||
import docspell.pubsub.naive.PubSubConfig
|
||||
@ -42,8 +43,13 @@ case class Config(
|
||||
updateCheck: UpdateCheckConfig
|
||||
) {
|
||||
|
||||
def pubSubConfig: PubSubConfig =
|
||||
PubSubConfig(appId, baseUrl / "internal" / "pubsub", 100)
|
||||
def pubSubConfig(headerValue: Ident): PubSubConfig =
|
||||
PubSubConfig(
|
||||
appId,
|
||||
baseUrl / "internal" / "pubsub",
|
||||
100,
|
||||
InternalHeader.header(headerValue.id)
|
||||
)
|
||||
}
|
||||
|
||||
object Config {
|
||||
|
@ -16,6 +16,7 @@ import docspell.common.Pools
|
||||
import docspell.joex.routes._
|
||||
import docspell.pubsub.naive.NaivePubSub
|
||||
import docspell.store.Store
|
||||
import docspell.store.records.RInternalSetting
|
||||
|
||||
import org.http4s.HttpApp
|
||||
import org.http4s.blaze.client.BlazeClientBuilder
|
||||
@ -43,13 +44,20 @@ object JoexServer {
|
||||
cfg.files.chunkSize,
|
||||
pools.connectEC
|
||||
)
|
||||
settings <- Resource.eval(store.transact(RInternalSetting.create))
|
||||
httpClient <- BlazeClientBuilder[F].resource
|
||||
pubSub <- NaivePubSub(cfg.pubSubConfig, store, httpClient)(Topics.all.map(_.topic))
|
||||
pubSub <- NaivePubSub(
|
||||
cfg.pubSubConfig(settings.internalRouteKey),
|
||||
store,
|
||||
httpClient
|
||||
)(Topics.all.map(_.topic))
|
||||
|
||||
joexApp <- JoexAppImpl.create[F](cfg, signal, store, httpClient, pubSub)
|
||||
|
||||
httpApp = Router(
|
||||
"/internal/pubsub" -> pubSub.receiveRoute,
|
||||
"/internal" -> InternalHeader(settings.internalRouteKey) {
|
||||
Router("pubsub" -> pubSub.receiveRoute)
|
||||
},
|
||||
"/api/info" -> InfoRoutes(cfg),
|
||||
"/api/v1" -> JoexRoutes(joexApp)
|
||||
).orNotFound
|
||||
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2020 Eike K. & Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package docspell.joex.routes
|
||||
|
||||
import cats.data.{Kleisli, OptionT}
|
||||
import cats.effect.kernel.Async
|
||||
import cats.implicits._
|
||||
|
||||
import docspell.common.Ident
|
||||
|
||||
import org.http4s._
|
||||
import org.http4s.dsl.Http4sDsl
|
||||
import org.http4s.server.AuthMiddleware
|
||||
import org.typelevel.ci._
|
||||
|
||||
// duplicated in restserver project
|
||||
object InternalHeader {
|
||||
|
||||
private val headerName = ci"Docspell-Internal-Api"
|
||||
|
||||
def header(value: String): Header.Raw =
|
||||
Header.Raw(headerName, value)
|
||||
|
||||
def apply[F[_]: Async](key: Ident)(routes: HttpRoutes[F]): HttpRoutes[F] = {
|
||||
val dsl: Http4sDsl[F] = new Http4sDsl[F] {}
|
||||
import dsl._
|
||||
|
||||
val authUser = checkSecret[F](key)
|
||||
|
||||
val onFailure: AuthedRoutes[String, F] =
|
||||
Kleisli(req => OptionT.liftF(NotFound(req.context)))
|
||||
|
||||
val middleware: AuthMiddleware[F, Unit] =
|
||||
AuthMiddleware(authUser, onFailure)
|
||||
|
||||
middleware(AuthedRoutes(authReq => routes.run(authReq.req)))
|
||||
}
|
||||
|
||||
private def checkSecret[F[_]: Async](
|
||||
key: Ident
|
||||
): Kleisli[F, Request[F], Either[String, Unit]] =
|
||||
Kleisli(req =>
|
||||
extractSecret[F](req)
|
||||
.filter(compareSecret(key.id))
|
||||
.toRight("Secret invalid")
|
||||
.map(_ => ())
|
||||
.pure[F]
|
||||
)
|
||||
|
||||
private def extractSecret[F[_]](req: Request[F]): Option[String] =
|
||||
req.headers.get(headerName).map(_.head.value)
|
||||
|
||||
private def compareSecret(s1: String)(s2: String): Boolean =
|
||||
s1 == s2
|
||||
}
|
Reference in New Issue
Block a user