Set stricter compile options and fix cookie data

This commit is contained in:
Eike Kettner 2019-09-28 22:17:45 +02:00
parent 46f1476418
commit 2ad1586d00
29 changed files with 94 additions and 93 deletions

View File

@ -10,14 +10,14 @@ val sharedSettings = Seq(
"-deprecation",
"-encoding", "UTF-8",
"-language:higherKinds",
"-language:postfixOps",
"-feature",
"-Werror", // fail when there are warnings
"-unchecked",
"-Xlint:_",
"-Ywarn-dead-code",
"-Ywarn-numeric-widen",
"-Ywarn-value-discard"
"-Wdead-code",
"-Wunused",
"-Wvalue-discard",
"-Wnumeric-widen"
),
scalacOptions in (Compile, console) :=
(scalacOptions.value.filter(o => !o.contains("Xlint")) ++ Seq("-Xlint:_,-unused")),

View File

@ -57,7 +57,7 @@ object Login {
if (at.sigInvalid(config.serverSecret)) Result.invalidAuth.pure[F]
else if (at.isExpired(config.sessionValid)) Result.invalidTime.pure[F]
else Result.ok(at).pure[F]
case Left(err) =>
case Left(_) =>
Result.invalidAuth.pure[F]
}
@ -73,7 +73,7 @@ object Login {
res <- if (data.exists(check(up.pass))) okResult
else Result.invalidAuth.pure[F]
} yield res
case Left(err) =>
case Left(_) =>
Result.invalidAuth.pure[F]
}
}

View File

@ -61,7 +61,7 @@ object OJob {
jobm = job.filter(canDelete)
del <- jobm.traverse(j => RJob.delete(j.id))
} yield del match {
case Some(n) => Right(JobCancelResult.Removed: JobCancelResult)
case Some(_) => Right(JobCancelResult.Removed: JobCancelResult)
case None => Left(mustCancel(job))
}

View File

@ -39,6 +39,13 @@ case class LenientUri(scheme: NonEmptyList[String]
rethrow.
flatMap(url => fs2.io.readInputStream(Sync[F].delay(url.openStream()), chunkSize, blocker, true))
def host: Option[String] =
authority.
map(a => a.indexOf(':') match {
case -1 => a
case n => a.substring(0, n)
})
def asString: String = {
val schemePart = scheme.toList.mkString(":")
val authPart = authority.map(a => s"//$a").getOrElse("")

View File

@ -11,7 +11,7 @@ case class ProcessItemArgs(meta: ProcessMeta, files: List[File]) {
case Nil => s"${meta.sourceAbbrev}: No files"
case n :: Nil => n
case n1 :: n2 :: Nil => s"$n1, $n2"
case more => s"${files.size} files from ${meta.sourceAbbrev}"
case _ => s"${files.size} files from ${meta.sourceAbbrev}"
}
}

View File

@ -27,8 +27,8 @@ object JoexServer {
joexApp <- JoexAppImpl.create[F](cfg, signal, connectEC, blocker)
httpApp = Router(
"/api/info" -> InfoRoutes(cfg),
"/api/v1" -> JoexRoutes(cfg, joexApp)
"/api/info" -> InfoRoutes(),
"/api/v1" -> JoexRoutes(joexApp)
).orNotFound
// With Middlewares in place

View File

@ -25,9 +25,9 @@ object CreateItem {
def fileMetas(itemId: Ident, now: Timestamp) = Stream.emits(ctx.args.files).
flatMap(f => ctx.store.bitpeace.get(f.fileMetaId.id).map(fm => (f, fm))).
collect({ case (f, Some(fm)) if validFiles.contains(fm.mimetype.baseType) => (f, fm) }).
collect({ case (f, Some(fm)) if validFiles.contains(fm.mimetype.baseType) => f }).
zipWithIndex.
evalMap({ case ((f, fm), index) =>
evalMap({ case (f, index) =>
Ident.randomId[F].map(id => RAttachment(id, itemId, f.fileMetaId, index.toInt, now, f.name))
}).
compile.toVector
@ -64,7 +64,11 @@ object CreateItem {
}
private def logDifferences[F[_]: Sync](ctx: Context[F, ProcessItemArgs], saved: Vector[RAttachment], saveCount: Int): F[Unit] =
ctx.logger.info("TODO log diffs")
if (ctx.args.files.size != saved.size) {
ctx.logger.warn(s"Not all given files (${ctx.args.files.size}) have been stored. Files retained: ${saved.size}; saveCount=$saveCount")
} else {
().pure[F]
}
private def storeItemError[F[_]: Sync](ctx: Context[F, ProcessItemArgs]): F[Unit] = {
val msg = "Inserting item failed. DB returned 0 update count!"

View File

@ -1,15 +1,15 @@
package docspell.joex.routes
import cats.effect.Sync
import docspell.joex.{BuildInfo, Config}
import docspell.joex.BuildInfo
import docspell.joexapi.model.VersionInfo
import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.dsl.Http4sDsl
object InfoRoutes {
def apply[F[_]: Sync](cfg: Config): HttpRoutes[F] = {
def apply[F[_]: Sync](): HttpRoutes[F] = {
val dsl = new Http4sDsl[F]{}
import dsl._
HttpRoutes.of[F] {

View File

@ -1,18 +1,18 @@
package docspell.joex.routes
import cats.implicits._
import cats.effect._
import cats.implicits._
import docspell.common.{Duration, Ident, Timestamp}
import docspell.joex.{Config, JoexApp}
import docspell.joex.JoexApp
import docspell.joexapi.model._
import docspell.store.records.{RJob, RJobLog}
import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.dsl.Http4sDsl
object JoexRoutes {
def apply[F[_]: ConcurrentEffect: Timer](cfg: Config, app: JoexApp[F]): HttpRoutes[F] = {
def apply[F[_]: ConcurrentEffect: Timer](app: JoexApp[F]): HttpRoutes[F] = {
val dsl = new Http4sDsl[F]{}
import dsl._
HttpRoutes.of[F] {

View File

@ -43,7 +43,7 @@ object Logger {
for {
q <- Queue.circularBuffer[F, LogEvent](bufferSize)
log = create(jobId, jobInfo, q)
fib <- Concurrent[F].start(q.dequeue.through(sink.receive).compile.drain)
_ <- Concurrent[F].start(q.dequeue.through(sink.receive).compile.drain)
} yield log
}

View File

@ -2,14 +2,14 @@ package docspell.restserver
import cats.effect._
import docspell.backend.auth.AuthToken
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.implicits._
import fs2.Stream
import org.http4s.server.middleware.Logger
import org.http4s.server.Router
import docspell.restserver.webapp._
import docspell.restserver.routes._
import docspell.restserver.webapp._
import fs2.Stream
import org.http4s.HttpRoutes
import org.http4s.implicits._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.middleware.Logger
import scala.concurrent.ExecutionContext
@ -22,12 +22,12 @@ object RestServer {
restApp <- RestAppImpl.create[F](cfg, connectEC, httpClientEc, blocker)
httpApp = Router(
"/api/info" -> routes.InfoRoutes(cfg),
"/api/info" -> routes.InfoRoutes(),
"/api/v1/open/" -> openRoutes(cfg, restApp),
"/api/v1/sec/" -> Authenticate(restApp.backend.login, cfg.auth) {
token => securedRoutes(cfg, restApp, token)
},
"/app/assets" -> WebjarRoutes.appRoutes[F](blocker, cfg),
"/app/assets" -> WebjarRoutes.appRoutes[F](blocker),
"/app" -> TemplateRoutes[F](blocker, cfg)
).orNotFound
@ -47,16 +47,16 @@ object RestServer {
def securedRoutes[F[_]: Effect](cfg: Config, restApp: RestApp[F], token: AuthToken): HttpRoutes[F] =
Router(
"auth" -> LoginRoutes.session(restApp.backend.login, cfg),
"tag" -> TagRoutes(restApp.backend, cfg, token),
"equipment" -> EquipmentRoutes(restApp.backend, cfg, token),
"organization" -> OrganizationRoutes(restApp.backend, cfg, token),
"person" -> PersonRoutes(restApp.backend, cfg, token),
"source" -> SourceRoutes(restApp.backend, cfg, token),
"user" -> UserRoutes(restApp.backend, cfg, token),
"collective" -> CollectiveRoutes(restApp.backend, cfg, token),
"queue" -> JobQueueRoutes(restApp.backend, cfg, token),
"item" -> ItemRoutes(restApp.backend, cfg, token),
"attachment" -> AttachmentRoutes(restApp.backend, cfg, token),
"tag" -> TagRoutes(restApp.backend, token),
"equipment" -> EquipmentRoutes(restApp.backend, token),
"organization" -> OrganizationRoutes(restApp.backend, token),
"person" -> PersonRoutes(restApp.backend, token),
"source" -> SourceRoutes(restApp.backend, token),
"user" -> UserRoutes(restApp.backend, token),
"collective" -> CollectiveRoutes(restApp.backend, token),
"queue" -> JobQueueRoutes(restApp.backend, token),
"item" -> ItemRoutes(restApp.backend, token),
"attachment" -> AttachmentRoutes(restApp.backend, token),
"upload" -> UploadRoutes.secured(restApp.backend, cfg, token)
)

View File

@ -11,9 +11,10 @@ case class CookieData(auth: AuthToken) {
def asString: String = auth.asString
def asCookie(cfg: Config): ResponseCookie = {
val domain = "" //cfg.baseUrl.hostAndPort
val sec = false //cfg.baseUrl.protocol.exists(_.endsWith("s"))
ResponseCookie(CookieData.cookieName, asString, domain = Some(domain), path = Some("/api/v1"), httpOnly = true, secure = sec)
val domain = cfg.baseUrl.host
val sec = cfg.baseUrl.scheme.exists(_.endsWith("s"))
val path = cfg.baseUrl.path/"api"/"v1"/"sec"
ResponseCookie(CookieData.cookieName, asString, domain = domain, path = Some(path.asString), httpOnly = true, secure = sec)
}
}
object CookieData {

View File

@ -243,7 +243,7 @@ trait Conversions {
def newUser[F[_]: Sync](u: User, cid: Ident): F[RUser] =
timeId.map { case (id, now) =>
RUser(id, u.login, cid, u.password.getOrElse(Password.empty), u.state, u.email, u.loginCount, u.lastLogin, u.created)
RUser(id, u.login, cid, u.password.getOrElse(Password.empty), u.state, u.email, 0, None, now)
}
def changeUser(u: User, cid: Ident): RUser =

View File

@ -1,5 +1,6 @@
package docspell.restserver.http4s
import cats.implicits._
import cats.Applicative
import org.http4s.{EntityEncoder, Header, Response}
import org.http4s.dsl.Http4sDsl
@ -16,14 +17,14 @@ trait ResponseGenerator[F[_]] {
e.fold(
a => UnprocessableEntity(a),
b => Ok(b)
)
).map(_.withHeaders(headers: _*))
}
implicit final class OptionResponse[A](o: Option[A]) {
def toResponse(headers: Header*)
(implicit F: Applicative[F]
, w0: EntityEncoder[F, A]): F[Response[F]] =
o.map(a => Ok(a)).getOrElse(NotFound())
o.map(a => Ok(a)).getOrElse(NotFound()).map(_.withHeaders(headers: _*))
}
}

View File

@ -12,13 +12,12 @@ import org.http4s.dsl.Http4sDsl
import org.http4s.headers._
import org.http4s.circe.CirceEntityEncoder._
import docspell.restapi.model._
import docspell.restserver.Config
import docspell.restserver.conv.Conversions
import org.http4s.headers.ETag.EntityTag
object AttachmentRoutes {
def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config, user: AuthToken): HttpRoutes[F] = {
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F]{}
import dsl._

View File

@ -15,7 +15,7 @@ object Authenticate {
def authenticateRequest[F[_]: Effect](auth: String => F[Login.Result])(req: Request[F]): F[Login.Result] =
CookieData.authenticator(req) match {
case Right(str) => auth(str)
case Left(err) => Login.Result.invalidAuth.pure[F]
case Left(_) => Login.Result.invalidAuth.pure[F]
}

View File

@ -5,17 +5,16 @@ import cats.implicits._
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.restapi.model._
import docspell.restserver.Config
import docspell.restserver.conv.Conversions
import docspell.restserver.http4s.ResponseGenerator
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.dsl.Http4sDsl
object CollectiveRoutes {
def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config, user: AuthToken): HttpRoutes[F] = {
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] with ResponseGenerator[F] {}
import dsl._

View File

@ -6,7 +6,6 @@ import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.common.Ident
import docspell.restapi.model._
import docspell.restserver.Config
import docspell.restserver.conv.Conversions._
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityDecoder._
@ -15,7 +14,7 @@ import org.http4s.dsl.Http4sDsl
object EquipmentRoutes {
def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config, user: AuthToken): HttpRoutes[F] = {
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F]{}
import dsl._

View File

@ -2,14 +2,14 @@ package docspell.restserver.routes
import cats.effect.Sync
import docspell.restapi.model.VersionInfo
import docspell.restserver.{BuildInfo, Config}
import org.http4s.circe.CirceEntityEncoder._
import docspell.restserver.BuildInfo
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.dsl.Http4sDsl
object InfoRoutes {
def apply[F[_]: Sync](cfg: Config): HttpRoutes[F] = {
def apply[F[_]: Sync](): HttpRoutes[F] = {
val dsl = new Http4sDsl[F]{}
import dsl._
HttpRoutes.of[F] {

View File

@ -10,7 +10,6 @@ import org.http4s.dsl.Http4sDsl
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.circe.CirceEntityDecoder._
import docspell.restapi.model._
import docspell.restserver.Config
import docspell.common.syntax.all._
import docspell.restserver.conv.Conversions
import org.log4s._
@ -18,7 +17,7 @@ import org.log4s._
object ItemRoutes {
private[this] val logger = getLogger
def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config, user: AuthToken): HttpRoutes[F] = {
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F]{}
import dsl._
@ -40,13 +39,13 @@ object ItemRoutes {
resp <- result.map(r => Ok(r)).getOrElse(NotFound(BasicResult(false, "Not found.")))
} yield resp
case req@POST -> Root / Ident(id) / "confirm" =>
case POST -> Root / Ident(id) / "confirm" =>
for {
res <- backend.item.setState(id, ItemState.Confirmed, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Item data confirmed"))
} yield resp
case req@POST -> Root / Ident(id) / "unconfirm" =>
case POST -> Root / Ident(id) / "unconfirm" =>
for {
res <- backend.item.setState(id, ItemState.Created, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Item back to created."))

View File

@ -5,7 +5,6 @@ import cats.implicits._
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.common.Ident
import docspell.restserver.Config
import docspell.restserver.conv.Conversions
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityEncoder._
@ -13,7 +12,7 @@ import org.http4s.dsl.Http4sDsl
object JobQueueRoutes {
def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config, user: AuthToken): HttpRoutes[F] = {
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] {}
import dsl._

View File

@ -4,19 +4,18 @@ import cats.effect._
import cats.implicits._
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.circe.CirceEntityDecoder._
import docspell.restapi.model._
import docspell.restserver.Config
import docspell.restserver.conv.Conversions._
import ParamDecoder._
import docspell.common.Ident
import docspell.restapi.model._
import docspell.restserver.conv.Conversions._
import docspell.restserver.routes.ParamDecoder._
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.dsl.Http4sDsl
object OrganizationRoutes {
def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config, user: AuthToken): HttpRoutes[F] = {
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F]{}
import dsl._

View File

@ -4,22 +4,21 @@ import cats.effect._
import cats.implicits._
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.circe.CirceEntityDecoder._
import docspell.restapi.model._
import docspell.restserver.Config
import docspell.restserver.conv.Conversions._
import docspell.common.Ident
import docspell.common.syntax.all._
import ParamDecoder._
import docspell.restapi.model._
import docspell.restserver.conv.Conversions._
import docspell.restserver.routes.ParamDecoder._
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.dsl.Http4sDsl
import org.log4s._
object PersonRoutes {
private[this] val logger = getLogger
def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config, user: AuthToken): HttpRoutes[F] = {
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F]{}
import dsl._

View File

@ -6,7 +6,6 @@ import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.common.Ident
import docspell.restapi.model._
import docspell.restserver.Config
import docspell.restserver.conv.Conversions._
import docspell.restserver.http4s.ResponseGenerator
import org.http4s.HttpRoutes
@ -16,7 +15,7 @@ import org.http4s.dsl.Http4sDsl
object SourceRoutes {
def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config, user: AuthToken): HttpRoutes[F] = {
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] with ResponseGenerator[F] {}
import dsl._

View File

@ -6,7 +6,6 @@ import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.common.Ident
import docspell.restapi.model._
import docspell.restserver.Config
import docspell.restserver.conv.Conversions._
import docspell.restserver.http4s.ResponseGenerator
import org.http4s.HttpRoutes
@ -16,7 +15,7 @@ import org.http4s.dsl.Http4sDsl
object TagRoutes {
def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config, user: AuthToken): HttpRoutes[F] = {
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] with ResponseGenerator[F] {}
import dsl._

View File

@ -6,7 +6,6 @@ import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.common.Ident
import docspell.restapi.model._
import docspell.restserver.Config
import docspell.restserver.conv.Conversions._
import docspell.restserver.http4s.ResponseGenerator
import org.http4s.HttpRoutes
@ -16,7 +15,7 @@ import org.http4s.dsl.Http4sDsl
object UserRoutes {
def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config, user: AuthToken): HttpRoutes[F] = {
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] with ResponseGenerator[F] {}
import dsl._

View File

@ -36,7 +36,7 @@ object TemplateRoutes {
case GET -> Root / "doc" =>
for {
templ <- docTemplate
resp <- Ok(DocData(cfg).render(templ), `Content-Type`(`text/html`))
resp <- Ok(DocData().render(templ), `Content-Type`(`text/html`))
} yield resp
}
}
@ -51,7 +51,7 @@ object TemplateRoutes {
}
def loadUrl[F[_]: Sync](url: URL, blocker: Blocker)(implicit C: ContextShift[F]): F[String] =
Stream.bracket(Sync[F].delay(url.openStream))(in => Sync[F].delay(in.close)).
Stream.bracket(Sync[F].delay(url.openStream))(in => Sync[F].delay(in.close())).
flatMap(in => io.readInputStream(in.pure[F], 64 * 1024, blocker, false)).
through(text.utf8Decode).
compile.fold("")(_ + _)
@ -75,7 +75,7 @@ object TemplateRoutes {
case class DocData(swaggerRoot: String, openapiSpec: String)
object DocData {
def apply(cfg: Config): DocData =
def apply(): DocData =
DocData("/app/assets" + Webjars.swaggerui, s"/app/assets/${BuildInfo.name}/${BuildInfo.version}/docspell-openapi.yml")
implicit def yamuscaValueConverter: ValueConverter[DocData] =

View File

@ -7,11 +7,9 @@ import org.http4s.server.staticcontent.webjarService
import org.http4s.server.staticcontent.NoopCacheStrategy
import org.http4s.server.staticcontent.WebjarService.{WebjarAsset, Config => WebjarConfig}
import docspell.restserver.Config
object WebjarRoutes {
def appRoutes[F[_]: Effect](blocker: Blocker, cfg: Config)(implicit C: ContextShift[F]): HttpRoutes[F] = {
def appRoutes[F[_]: Effect](blocker: Blocker)(implicit C: ContextShift[F]): HttpRoutes[F] = {
webjarService(
WebjarConfig(
filter = assetFilter,

View File

@ -109,7 +109,7 @@ object RJob {
def setScheduled(jobId: Ident, workerId: Ident): ConnectionIO[Int] = {
for {
_ <- incrementRetries(jobId)
n <- updateRow(table, and(id is jobId, or(worker isNull, worker is workerId), state isOneOf Seq[JobState](JobState.Waiting, JobState.Stuck)), commas(
n <- updateRow(table, and(id is jobId, or(worker.isNull, worker is workerId), state isOneOf Seq[JobState](JobState.Waiting, JobState.Stuck)), commas(
state setTo (JobState.Scheduled: JobState),
worker setTo workerId
)).update.run