An extremely simple user-authentication service.

app.moon 1.8KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. lapis = require "lapis"
  2. bcrypt = require "bcrypt"
  3. config = require("lapis.config").get!
  4. import Users from require "models"
  5. import api, abort, assert_model from require "helpers"
  6. class extends lapis.Application
  7. [console: "/console/#{config.secret}"]: =>
  8. if Users\count! < 1 or @session.id == 1
  9. return console.make(env: "all")(@)
  10. else
  11. return status: 401, "401 - Unauthorized"
  12. [authenticate: "/0/auth"]: api {
  13. POST: =>
  14. -- find user by name or id if specified
  15. local user
  16. if @params.name
  17. user = Users\find name: @params.name
  18. elseif @params.id
  19. user = Users\find id: @params.id
  20. abort "No such user." unless user
  21. -- if a user by that name exists, see if the password is correct
  22. if user
  23. unless bcrypt.verify(@params.password, user.digest)
  24. abort "Incorrect password."
  25. -- else create a user
  26. elseif @params.password
  27. assert_valid(@params, {
  28. { "name", exists: true, min_length: 1, max_length: 255, matches_pattern: "%w+" }
  29. { "password", exists: true, min_length: 8, max_length: 255 }
  30. })
  31. -- TODO passwords should be checked against known breached passwords
  32. -- TODO passwords should be required to follow a few other basic security checks
  33. -- actually, these are invalidated just by checking against breached passwords I think
  34. user = assert_model Users\create {
  35. name: @params.name
  36. digest: bcrypt.digest(@params.password, config.digest_rounds)
  37. }
  38. -- if a password wasn't specified...
  39. else
  40. abort "Must specify name or id, and password."
  41. return name: user.name, id: user.id
  42. }
  43. [name: "/0/:id[%d]"]: api {
  44. GET: =>
  45. if user = Users\find id: @params.id
  46. return name: user.name
  47. else
  48. abort "No such user."
  49. }