Software /
code /
prosody-modules
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 |
parent | 607:121762432eb1 |
child | 651: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 |