~siegfriedehret/urlhut

9aeea41478738bf6b6ada387119e0a3e2e334395 — Siegfried Ehret 2 years ago 38c3281
🛖 add auth on pages
A src/lib/auth.nim => src/lib/auth.nim +21 -0
@@ 0,0 1,21 @@
import jester
import karax/vdom
import ../views/[common, unauthorized]

proc isAuthOK(req: Request, token: string): bool =
  if token == "":
    return true

  try:
    var t = req.cookies["TOKEN"]
    if t == token:
      return true
  except KeyError:
    discard
  return false

proc renderWithAuth*(req: Request, token: string, body: VNode): string =
  if isAuthOK(req, token):
    result = renderPage(body)
  else:
    result = renderPage(renderUnauthorized())

M src/lib/server.nim => src/lib/server.nim +32 -20
@@ 1,28 1,40 @@
import std/strutils
from os import getEnv
import jester
import ../routes/[edit, home, new, tags], ../views/[common, forms]
import ../lib/auth, ../routes/[edit, home, new, tags], ../views/[forms]

router hutRouter:
  get "/":
    resp renderPage(renderHome())
  get "/new":
    resp renderPage(renderNew())
  get "/edit/@id":
    resp renderPage(renderEdit(@"id"))
  get "/tags":
    resp renderPage(renderTagsList())
  get "/tags/@name":
    resp renderPage(renderTag(@"name"))
  post "/api/v1/url":
    saveUrl(request)
    redirect("/")
  post "/api/v1/url/delete":
    removeUrl(request)
    redirect("/")

proc startServer*() =
proc startServer*(token: string) =
  let port = getEnv("PORT", "3000")
  let settings = newSettings(port = Port(parseInt(port)))

  router hutRouter:
    get "/":
      resp renderWithAuth(request, token, renderHome())
    get "/new":
      resp renderWithAuth(request, token, renderNew())
    get "/edit/@id":
      resp renderWithAuth(request, token, renderEdit(@"id"))
    get "/tags":
      resp renderWithAuth(request, token, renderTagsList())
    get "/tags/@name":
      resp renderWithAuth(request, token, renderTag(@"name"))
    post "/api/v1/url":
      saveUrl(request)
      redirect("/")
    post "/api/v1/url/delete":
      removeUrl(request)
      redirect("/")
    post "/api/v1/token":
      try:
        let t = request.formData.getOrDefault("token").body
        if t == token:
          setCookie("TOKEN", value = t, path = "/", secure = true,
              httpOnly = true)
      except KeyError:
        # TODO show error message
        discard
      # TODO redirect to requested page.
      redirect("/")

  var jester = initJester(hutRouter, settings = settings)
  jester.serve()

A src/routes/token.nim => src/routes/token.nim +1 -0
@@ 0,0 1,1 @@


M src/urlhut.nim => src/urlhut.nim +7 -3
@@ 1,13 1,18 @@
# This is just an example to get you started. A typical binary package
# uses this file as the main entry point of the application.
import std/logging
from os import getEnv
import dotenv
import ./lib/[db, server]

proc ctrlc() {.noconv.} =
  info("🛖 is stopping")
  closeDb()
  quit()

when isMainModule:
  info("🛖 is starting")

  addHandler(newConsoleLogger())
  setLogFilter(lvlError)



@@ 15,6 20,5 @@ when isMainModule:
  load()
  initDb()

  info("🛖 is starting")

  startServer()
  let token = getEnv("TOKEN", "")
  startServer(token)

A src/views/unauthorized.nim => src/views/unauthorized.nim +14 -0
@@ 0,0 1,14 @@
import karax/[karaxdsl, vdom]

proc renderUnauthorized*(): VNode =
  result = buildHtml(tdiv):
    p: text "Error 401: unauthorized"
    p: text "Do you have a token?"
    form(`method` = "post", action = "/api/v1/token",
          enctype = "multipart/form-data"):
      label(`for` = "token"):
        text "Token"
      input(`type` = "text", name = "token", id = "token", autofocus = "",
                placeholder = "Enter your token...")
      button(`type` = "submit"):
        text "submit"

M urlhut.nimble => urlhut.nimble +1 -1
@@ 10,7 10,7 @@ bin           = @["urlhut"]

# Dependencies

requires "nim >= 1.6.0"
requires "nim >= 1.6.6"
requires "jester >= 0.5.0"
requires "karax#fa4a2dc"
requires "dotenv >= 2.0.0"