Merge pull request #2174 from rosysong/lease-status
[oweals/luci.git] / modules / luci-mod-rpc / luasrc / controller / rpc.lua
1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
3 -- Licensed to the public under the Apache License 2.0.
4
5 module("luci.controller.rpc", package.seeall)
6
7
8 function session_retrieve(sid, allowed_users)
9         local util = require "luci.util"
10         local sdat = util.ubus("session", "get", {
11                 ubus_rpc_session = sid
12         })
13
14         if type(sdat) == "table" and
15            type(sdat.values) == "table" and
16            type(sdat.values.token) == "string" and
17            type(sdat.values.username) == "string" and
18            util.contains(allowed_users, sdat.values.username)
19         then
20                 return sid, sdat.values
21         end
22
23         return nil
24 end
25
26 function authenticator(validator, accs)
27         local http = require "luci.http"
28         local ctrl = require "luci.controller.rpc"
29         local auth = http.formvalue("auth", true) or http.getcookie("sysauth")
30
31         if auth then -- if authentication token was given
32                 local sid, sdat = ctrl.session_retrieve(auth, accs)
33                 if sdat then -- if given token is valid
34                         return sdat.username, sid
35                 end
36                 http.status(403, "Forbidden")
37         end
38 end
39
40
41 function index()
42         local ctrl = require "luci.controller.rpc"
43
44         local rpc = node("rpc")
45         rpc.sysauth = "root"
46         rpc.sysauth_authenticator = ctrl.authenticator
47         rpc.notemplate = true
48
49         entry({"rpc", "uci"}, call("rpc_uci"))
50         entry({"rpc", "fs"}, call("rpc_fs"))
51         entry({"rpc", "sys"}, call("rpc_sys"))
52         entry({"rpc", "ipkg"}, call("rpc_ipkg"))
53         entry({"rpc", "ip"}, call("rpc_ip"))
54         entry({"rpc", "auth"}, call("rpc_auth")).sysauth = false
55 end
56
57 function rpc_auth()
58         local ctrl    = require "luci.controller.rpc"
59         local jsonrpc = require "luci.jsonrpc"
60         local http    = require "luci.http"
61         local sys     = require "luci.sys"
62         local ltn12   = require "luci.ltn12"
63         local util    = require "luci.util"
64
65         local server = {}
66         server.challenge = function(user, pass)
67                 local config = require "luci.config"
68                 local login = util.ubus("session", "login", {
69                         username = user,
70                         password = pass,
71                         timeout  = tonumber(config.sauth.sessiontime)
72                 })
73
74                 if type(login) == "table" and
75                    type(login.ubus_rpc_session) == "string"
76                 then
77                         util.ubus("session", "set", {
78                                 ubus_rpc_session = login.ubus_rpc_session,
79                                 values = {
80                                         token = sys.uniqueid(16)
81                                 }
82                         })
83
84                         local sid, sdat = ctrl.session_retrieve(login.ubus_rpc_session, { user })
85                         if sdat then
86                                 return {
87                                         sid = sid,
88                                         token = sdat.token
89                                 }
90                         end
91                 end
92
93                 return nil
94         end
95
96         server.login = function(...)
97                 local challenge = server.challenge(...)
98                 if challenge then
99                         http.header("Set-Cookie", 'sysauth=%s; path=%s' %{
100                                 challenge.sid,
101                                 http.getenv("SCRIPT_NAME")
102                         })
103                         return challenge.sid
104                 end
105         end
106
107         http.prepare_content("application/json")
108         ltn12.pump.all(jsonrpc.handle(server, http.source()), http.write)
109 end
110
111 function rpc_uci()
112         if not pcall(require, "luci.model.uci") then
113                 luci.http.status(404, "Not Found")
114                 return nil
115         end
116         local uci     = require "luci.jsonrpcbind.uci"
117         local jsonrpc = require "luci.jsonrpc"
118         local http    = require "luci.http"
119         local ltn12   = require "luci.ltn12"
120
121         http.prepare_content("application/json")
122         ltn12.pump.all(jsonrpc.handle(uci, http.source()), http.write)
123 end
124
125 function rpc_fs()
126         local util    = require "luci.util"
127         local io      = require "io"
128         local fs2     = util.clone(require "nixio.fs")
129         local jsonrpc = require "luci.jsonrpc"
130         local http    = require "luci.http"
131         local ltn12   = require "luci.ltn12"
132
133         function fs2.readfile(filename)
134                 local stat, mime = pcall(require, "mime")
135                 if not stat then
136                         error("Base64 support not available. Please install LuaSocket.")
137                 end
138
139                 local fp = io.open(filename)
140                 if not fp then
141                         return nil
142                 end
143
144                 local output = {}
145                 local sink = ltn12.sink.table(output)
146                 local source = ltn12.source.chain(ltn12.source.file(fp), mime.encode("base64"))
147                 return ltn12.pump.all(source, sink) and table.concat(output)
148         end
149
150         function fs2.writefile(filename, data)
151                 local stat, mime = pcall(require, "mime")
152                 if not stat then
153                         error("Base64 support not available. Please install LuaSocket.")
154                 end
155
156                 local  file = io.open(filename, "w")
157                 local  sink = file and ltn12.sink.chain(mime.decode("base64"), ltn12.sink.file(file))
158                 return sink and ltn12.pump.all(ltn12.source.string(data), sink) or false
159         end
160
161         http.prepare_content("application/json")
162         ltn12.pump.all(jsonrpc.handle(fs2, http.source()), http.write)
163 end
164
165 function rpc_sys()
166         local util    = require "luci.util"
167         local sys     = require "luci.sys"
168         local jsonrpc = require "luci.jsonrpc"
169         local http    = require "luci.http"
170         local ltn12   = require "luci.ltn12"
171
172         local sys2 = util.clone(sys)
173               sys2.net = util.clone(sys.net)
174               sys2.wifi = util.clone(sys.wifi)
175
176         function sys2.wifi.getiwinfo(ifname, operation)
177                 local iw = sys.wifi.getiwinfo(ifname)
178                 if iw then
179                         if operation then
180                                 assert(type(iwinfo[iw.type][operation]) == "function")
181                                 return iw[operation]
182                         end
183
184                         local n, f
185                         local rv = { ifname = ifname }
186                         for n, f in pairs(iwinfo[iw.type]) do
187                                 if type(f) == "function" and
188                                    n ~= "scanlist" and n ~= "countrylist"
189                                 then
190                                         rv[n] = iw[n]
191                                 end
192                         end
193                         return rv
194                 end
195                 return nil
196         end
197
198         http.prepare_content("application/json")
199         ltn12.pump.all(jsonrpc.handle(sys2, http.source()), http.write)
200 end
201
202 function rpc_ipkg()
203         if not pcall(require, "luci.model.ipkg") then
204                 luci.http.status(404, "Not Found")
205                 return nil
206         end
207         local ipkg    = require "luci.model.ipkg"
208         local jsonrpc = require "luci.jsonrpc"
209         local http    = require "luci.http"
210         local ltn12   = require "luci.ltn12"
211
212         http.prepare_content("application/json")
213         ltn12.pump.all(jsonrpc.handle(ipkg, http.source()), http.write)
214 end
215
216 function rpc_ip()
217         if not pcall(require, "luci.ip") then
218                 luci.http.status(404, "Not Found")
219                 return nil
220         end
221
222         local util    = require "luci.util"
223         local ip      = require "luci.ip"
224         local jsonrpc = require "luci.jsonrpc"
225         local http    = require "luci.http"
226         local ltn12   = require "luci.ltn12"
227
228         local ip2 = util.clone(ip)
229
230         local _, n
231         for _, n in ipairs({ "new", "IPv4", "IPv6", "MAC" }) do
232                 ip2[n] = function(address, netmask, operation, argument)
233                         local cidr = ip[n](address, netmask)
234                         if cidr and operation then
235                                 assert(type(cidr[operation]) == "function")
236                                 local cidr2 = cidr[operation](cidr, argument)
237                                 return (type(cidr2) == "userdata") and cidr2:string() or cidr2
238                         end
239                         return (type(cidr) == "userdata") and cidr:string() or cidr
240                 end
241         end
242
243         http.prepare_content("application/json")
244         ltn12.pump.all(jsonrpc.handle(ip2, http.source()), http.write)
245 end