comparison mod_register_json/mod_register_json.lua @ 648:6f0e0d6790a7

mod_register_json: updated to current HTTP API.
author Marco Cirillo <maranda@lightwitch.org>
date Sun, 29 Apr 2012 13:05:46 +0000
parents 121762432eb1
children 78a23a7dc613
comparison
equal deleted inserted replaced
647:6b3606e0a6e7 648:6f0e0d6790a7
7 local jid_prep = require "util.jid".prep 7 local jid_prep = require "util.jid".prep
8 local jid_split = require "util.jid".split 8 local jid_split = require "util.jid".split
9 local usermanager = require "core.usermanager" 9 local usermanager = require "core.usermanager"
10 local b64_decode = require "util.encodings".base64.decode 10 local b64_decode = require "util.encodings".base64.decode
11 local json_decode = require "util.json".decode 11 local json_decode = require "util.json".decode
12 local httpserver = require "net.httpserver"
13 local os_time = os.time 12 local os_time = os.time
14 local nodeprep = require "util.encodings".stringprep.nodeprep 13 local nodeprep = require "util.encodings".stringprep.nodeprep
15 14
16 module.host = "*" -- HTTP/BOSH Servlets need to be global. 15 module:depends("http")
16 module:set_global()
17 17
18 -- Pick up configuration. 18 -- Pick up configuration.
19 19
20 local set_realm_name = module:get_option_string("reg_servlet_realm", "Restricted") 20 local set_realm_name = module:get_option_string("reg_servlet_realm", "Restricted")
21 local base_path = module:get_option_string("reg_servlet_base", "/register_account/")
21 local throttle_time = module:get_option_number("reg_servlet_ttime", nil) 22 local throttle_time = module:get_option_number("reg_servlet_ttime", nil)
22 local whitelist = module:get_option_set("reg_servlet_wl", {}) 23 local whitelist = module:get_option_set("reg_servlet_wl", {})
23 local blacklist = module:get_option_set("reg_servlet_bl", {}) 24 local blacklist = module:get_option_set("reg_servlet_bl", {})
24 local ports = module:get_option_array("reg_servlet_ports", {{ port = 9280 }})
25 local recent_ips = {} 25 local recent_ips = {}
26 26
27 -- Begin 27 -- Begin
28 28
29 local function http_response(code, message, extra_headers) 29 local function http_response(event, code, message, headers)
30 local response = { 30 local response = event.response
31 status = code .. " " .. message, 31
32 body = message .. "\n" } 32 if headers then
33 if extra_headers then response.headers = extra_headers end 33 for header, data in pairs(headers) do response.headers[header] = data end
34 return response 34 end
35
36 response.headers.content_type = "application/json"
37 response.status_code = code
38 response:send(message)
35 end 39 end
36 40
37 local function handle_req(method, body, request) 41 local function handle_req(event)
42 local request = event.request
43 local body = request.body
44
38 if request.method ~= "POST" then 45 if request.method ~= "POST" then
39 return http_response(405, "Bad method...", {["Allow"] = "POST"}) 46 return http_response(event, 405, "Bad method...", {["Allow"] = "POST"})
40 end 47 end
41 if not request.headers["authorization"] then 48 if not request.headers["authorization"] then
42 return http_response(401, "No... No...", {["WWW-Authenticate"]='Basic realm="'.. set_realm_name ..'"'}) 49 return http_response(event, 401, "No... No...", {["WWW-Authenticate"]='Basic realm="'.. set_realm_name ..'"'})
43 end 50 end
44 51
45 local user, password = b64_decode(request.headers.authorization:match("[^ ]*$") or ""):match("([^:]*):(.*)") 52 local user, password = b64_decode(request.headers.authorization:match("[^ ]*$") or ""):match("([^:]*):(.*)")
46 user = jid_prep(user) 53 user = jid_prep(user)
47 if not user or not password then return http_response(400, "What's this..?") end 54 if not user or not password then return http_response(event, 400, "What's this..?") end
48 local user_node, user_host = jid_split(user) 55 local user_node, user_host = jid_split(user)
49 if not hosts[user_host] then return http_response(401, "Negative.") end 56 if not hosts[user_host] then return http_response(event, 401, "Negative.") end
50 57
51 module:log("warn", "%s is authing to submit a new user registration data", user) 58 module:log("warn", "%s is authing to submit a new user registration data", user)
52 if not usermanager.test_password(user_node, user_host, password) then 59 if not usermanager.test_password(user_node, user_host, password) then
53 module:log("warn", "%s failed authentication", user) 60 module:log("warn", "%s failed authentication", user)
54 return http_response(401, "Who the hell are you?! Guards!") 61 return http_response(event, 401, "Who the hell are you?! Guards!")
55 end 62 end
56 63
57 local req_body 64 local req_body
58 -- We check that what we have is valid JSON wise else we throw an error... 65 -- We check that what we have is valid JSON wise else we throw an error...
59 if not pcall(function() req_body = json_decode(body) end) then 66 if not pcall(function() req_body = json_decode(body) end) then
60 module:log("debug", "JSON data submitted for user registration by %s failed to Decode.", user) 67 module:log("debug", "JSON data submitted for user registration by %s failed to Decode.", user)
61 return http_response(400, "JSON Decoding failed.") 68 return http_response(event, 400, "JSON Decoding failed.")
62 else 69 else
63 -- Decode JSON data and check that all bits are there else throw an error 70 -- Decode JSON data and check that all bits are there else throw an error
64 req_body = json_decode(body) 71 req_body = json_decode(body)
65 if req_body["username"] == nil or req_body["password"] == nil or req_body["host"] == nil or req_body["ip"] == nil then 72 if req_body["username"] == nil or req_body["password"] == nil or req_body["host"] == nil or req_body["ip"] == nil then
66 module:log("debug", "%s supplied an insufficent number of elements or wrong elements for the JSON registration", user) 73 module:log("debug", "%s supplied an insufficent number of elements or wrong elements for the JSON registration", user)
67 return http_response(400, "Invalid syntax.") 74 return http_response(event, 400, "Invalid syntax.")
68 end 75 end
69 -- Check if user is an admin of said host 76 -- Check if user is an admin of said host
70 if not usermanager.is_admin(user, req_body["host"]) then 77 if not usermanager.is_admin(user, req_body["host"]) then
71 module:log("warn", "%s tried to submit registration data for %s but he's not an admin", user, req_body["host"]) 78 module:log("warn", "%s tried to submit registration data for %s but he's not an admin", user, req_body["host"])
72 return http_response(401, "I obey only to my masters... Have a nice day.") 79 return http_response(event, 401, "I obey only to my masters... Have a nice day.")
73 else 80 else
74 -- Checks for both Throttling/Whitelist and Blacklist (basically copycatted from prosody's register.lua code) 81 -- Checks for both Throttling/Whitelist and Blacklist (basically copycatted from prosody's register.lua code)
75 if blacklist:contains(req_body["ip"]) then module:log("warn", "Attempt of reg. submission to the JSON servlet from blacklisted address: %s", req_body["ip"]) ; return http_response(403, "The specified address is blacklisted, sorry sorry.") end 82 if blacklist:contains(req_body["ip"]) then module:log("warn", "Attempt of reg. submission to the JSON servlet from blacklisted address: %s", req_body["ip"]) ; return http_response(403, "The specified address is blacklisted, sorry sorry.") end
76 if throttle_time and not whitelist:contains(req_body["ip"]) then 83 if throttle_time and not whitelist:contains(req_body["ip"]) then
77 if not recent_ips[req_body["ip"]] then 84 if not recent_ips[req_body["ip"]] then
90 -- And nodeprep the username 97 -- And nodeprep the username
91 local username = nodeprep(req_body["username"]) 98 local username = nodeprep(req_body["username"])
92 if not usermanager.user_exists(username, req_body["host"]) then 99 if not usermanager.user_exists(username, req_body["host"]) then
93 if not username then 100 if not username then
94 module:log("debug", "%s supplied an username containing invalid characters: %s", user, username) 101 module:log("debug", "%s supplied an username containing invalid characters: %s", user, username)
95 return http_response(406, "Supplied username contains invalid characters, see RFC 6122.") 102 return http_response(event, 406, "Supplied username contains invalid characters, see RFC 6122.")
96 else 103 else
97 local ok, error = usermanager.create_user(username, req_body["password"], req_body["host"]) 104 local ok, error = usermanager.create_user(username, req_body["password"], req_body["host"])
98 if ok then 105 if ok then
99 hosts[req_body["host"]].events.fire_event("user-registered", { username = username, host = req_body["host"], source = "mod_register_json", session = { ip = req_body["ip"] } }) 106 hosts[req_body["host"]].events.fire_event("user-registered", { username = username, host = req_body["host"], source = "mod_register_json", session = { ip = req_body["ip"] } })
100 module:log("debug", "%s registration data submission for %s@%s is successful", user, username, req_body["host"]) 107 module:log("debug", "%s registration data submission for %s@%s is successful", user, username, req_body["host"])
101 return http_response(200, "Done.") 108 return http_response(event, 200, "Done.")
102 else 109 else
103 module:log("error", "user creation failed: "..error) 110 module:log("error", "user creation failed: "..error)
104 return http_response(500, "Encountered server error while creating the user: "..error) 111 return http_response(event 500, "Encountered server error while creating the user: "..error)
105 end 112 end
106 end 113 end
107 else 114 else
108 module:log("debug", "%s registration data submission for %s failed (user already exists)", user, username) 115 module:log("debug", "%s registration data submission for %s failed (user already exists)", user, username)
109 return http_response(409, "User already exists.") 116 return http_response(event, 409, "User already exists.")
110 end 117 end
111 end 118 end
112 end 119 end
113 end 120 end
114 121
115 -- Set it up! 122 -- Set it up!
116 123
117 function setup() 124 module:provides("http", {
118 for id, options in ipairs(ports) do 125 default_path = base_path,
119 if not options.port then 126 route = {
120 if not options.ssl then ports[id].port = 9280 127 ["GET /"] = handle_req,
121 else ports[id].port = 9443 end 128 ["POST /"] = handle_req
122 elseif options.port == 9280 and options.ssl then ports[id].port = 9443 end end 129 }
123 httpserver.new_from_config(ports, handle_req, { base = "register_account" }) 130 })
124 end
125
126 if prosody.start_time then -- already started
127 setup()
128 else
129 module:hook("server-started", setup)
130 end