auth.lua 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. -- Minetest: builtin/auth.lua
  2. --
  3. -- Builtin authentication handler
  4. --
  5. -- Make the auth object private, deny access to mods
  6. local core_auth = core.auth
  7. core.auth = nil
  8. core.builtin_auth_handler = {
  9. get_auth = function(name)
  10. assert(type(name) == "string")
  11. local auth_entry = core_auth.read(name)
  12. -- If no such auth found, return nil
  13. if not auth_entry then
  14. return nil
  15. end
  16. -- Figure out what privileges the player should have.
  17. -- Take a copy of the privilege table
  18. local privileges = {}
  19. for priv, _ in pairs(auth_entry.privileges) do
  20. privileges[priv] = true
  21. end
  22. -- If singleplayer, give all privileges except those marked as give_to_singleplayer = false
  23. if core.is_singleplayer() then
  24. for priv, def in pairs(core.registered_privileges) do
  25. if def.give_to_singleplayer then
  26. privileges[priv] = true
  27. end
  28. end
  29. -- For the admin, give everything
  30. elseif name == core.settings:get("name") then
  31. for priv, def in pairs(core.registered_privileges) do
  32. if def.give_to_admin then
  33. privileges[priv] = true
  34. end
  35. end
  36. end
  37. -- All done
  38. return {
  39. password = auth_entry.password,
  40. privileges = privileges,
  41. last_login = auth_entry.last_login,
  42. }
  43. end,
  44. create_auth = function(name, password)
  45. assert(type(name) == "string")
  46. assert(type(password) == "string")
  47. core.log('info', "Built-in authentication handler adding player '"..name.."'")
  48. return core_auth.create({
  49. name = name,
  50. password = password,
  51. privileges = core.string_to_privs(core.settings:get("default_privs")),
  52. last_login = -1, -- Defer login time calculation until record_login (called by on_joinplayer)
  53. })
  54. end,
  55. delete_auth = function(name)
  56. assert(type(name) == "string")
  57. local auth_entry = core_auth.read(name)
  58. if not auth_entry then
  59. return false
  60. end
  61. core.log('info', "Built-in authentication handler deleting player '"..name.."'")
  62. return core_auth.delete(name)
  63. end,
  64. set_password = function(name, password)
  65. assert(type(name) == "string")
  66. assert(type(password) == "string")
  67. local auth_entry = core_auth.read(name)
  68. if not auth_entry then
  69. core.builtin_auth_handler.create_auth(name, password)
  70. else
  71. core.log('info', "Built-in authentication handler setting password of player '"..name.."'")
  72. auth_entry.password = password
  73. core_auth.save(auth_entry)
  74. end
  75. return true
  76. end,
  77. set_privileges = function(name, privileges)
  78. assert(type(name) == "string")
  79. assert(type(privileges) == "table")
  80. local auth_entry = core_auth.read(name)
  81. if not auth_entry then
  82. auth_entry = core.builtin_auth_handler.create_auth(name,
  83. core.get_password_hash(name,
  84. core.settings:get("default_password")))
  85. end
  86. local prev_privs = auth_entry.privileges
  87. auth_entry.privileges = privileges
  88. core_auth.save(auth_entry)
  89. for priv, value in pairs(privileges) do
  90. -- Warnings for improper API usage
  91. if value == false then
  92. core.log('deprecated', "`false` value given to `minetest.set_player_privs`, "..
  93. "this is almost certainly a bug, "..
  94. "granting a privilege rather than revoking it")
  95. elseif value ~= true then
  96. core.log('deprecated', "non-`true` value given to `minetest.set_player_privs`")
  97. end
  98. -- Run grant callbacks
  99. if prev_privs[priv] == nil then
  100. core.run_priv_callbacks(name, priv, nil, "grant")
  101. end
  102. end
  103. -- Run revoke callbacks
  104. for priv, _ in pairs(prev_privs) do
  105. if privileges[priv] == nil then
  106. core.run_priv_callbacks(name, priv, nil, "revoke")
  107. end
  108. end
  109. core.notify_authentication_modified(name)
  110. end,
  111. reload = function()
  112. core_auth.reload()
  113. return true
  114. end,
  115. record_login = function(name)
  116. assert(type(name) == "string")
  117. local auth_entry = core_auth.read(name)
  118. assert(auth_entry)
  119. auth_entry.last_login = os.time()
  120. core_auth.save(auth_entry)
  121. end,
  122. iterate = function()
  123. local names = {}
  124. local nameslist = core_auth.list_names()
  125. for k,v in pairs(nameslist) do
  126. names[v] = true
  127. end
  128. return pairs(names)
  129. end,
  130. }
  131. core.register_on_prejoinplayer(function(name, ip)
  132. if core.registered_auth_handler ~= nil then
  133. return -- Don't do anything if custom auth handler registered
  134. end
  135. local auth_entry = core_auth.read(name)
  136. if auth_entry ~= nil then
  137. return
  138. end
  139. local name_lower = name:lower()
  140. for k in core.builtin_auth_handler.iterate() do
  141. if k:lower() == name_lower then
  142. return string.format("\nCannot create new player called '%s'. "..
  143. "Another account called '%s' is already registered. "..
  144. "Please check the spelling if it's your account "..
  145. "or use a different nickname.", name, k)
  146. end
  147. end
  148. end)
  149. --
  150. -- Authentication API
  151. --
  152. function core.register_authentication_handler(handler)
  153. if core.registered_auth_handler then
  154. error("Add-on authentication handler already registered by "..core.registered_auth_handler_modname)
  155. end
  156. core.registered_auth_handler = handler
  157. core.registered_auth_handler_modname = core.get_current_modname()
  158. handler.mod_origin = core.registered_auth_handler_modname
  159. end
  160. function core.get_auth_handler()
  161. return core.registered_auth_handler or core.builtin_auth_handler
  162. end
  163. local function auth_pass(name)
  164. return function(...)
  165. local auth_handler = core.get_auth_handler()
  166. if auth_handler[name] then
  167. return auth_handler[name](...)
  168. end
  169. return false
  170. end
  171. end
  172. core.set_player_password = auth_pass("set_password")
  173. core.set_player_privs = auth_pass("set_privileges")
  174. core.remove_player_auth = auth_pass("delete_auth")
  175. core.auth_reload = auth_pass("reload")
  176. function core.change_player_privs(name, changes)
  177. local privs = core.get_player_privs(name)
  178. for priv, change in pairs(changes) do
  179. if change == true then
  180. privs[priv] = true
  181. elseif change == false then
  182. privs[priv] = nil
  183. else
  184. error("non-bool value given to `minetest.change_player_privs`")
  185. end
  186. end
  187. core.set_player_privs(name, privs)
  188. end
  189. local record_login = auth_pass("record_login")
  190. core.register_on_joinplayer(function(player)
  191. record_login(player:get_player_name())
  192. end)