Mercurial > prosody-modules
comparison mod_client_management/mod_client_management.lua @ 5653:62c6e17a5e9d
Merge
author | Stephen Paul Weber <singpolyma@singpolyma.net> |
---|---|
date | Mon, 18 Sep 2023 08:24:19 -0500 |
parents | f16edebb1305 |
children | c69320fc438b |
comparison
equal
deleted
inserted
replaced
5652:eade7ff9f52c | 5653:62c6e17a5e9d |
---|---|
8 local jid = require "util.jid"; | 8 local jid = require "util.jid"; |
9 local st = require "util.stanza"; | 9 local st = require "util.stanza"; |
10 | 10 |
11 local strict = module:get_option_boolean("enforce_client_ids", false); | 11 local strict = module:get_option_boolean("enforce_client_ids", false); |
12 | 12 |
13 module:default_permission("prosody:user", ":list-clients"); | 13 module:default_permission("prosody:registered", ":list-clients"); |
14 module:default_permission("prosody:user", ":manage-clients"); | 14 module:default_permission("prosody:registered", ":manage-clients"); |
15 | 15 |
16 local tokenauth = module:depends("tokenauth"); | 16 local tokenauth = module:depends("tokenauth"); |
17 local mod_fast = module:depends("sasl2_fast"); | 17 local mod_fast = module:depends("sasl2_fast"); |
18 | 18 |
19 local client_store = assert(module:open_store("clients", "keyval+")); | 19 local client_store = assert(module:open_store("clients", "keyval+")); |
33 local sasl_agent = sasl_handler and sasl_handler.user_agent; | 33 local sasl_agent = sasl_handler and sasl_handler.user_agent; |
34 local token_agent = token_info and token_info.data and token_info.data.oauth2_client; | 34 local token_agent = token_info and token_info.data and token_info.data.oauth2_client; |
35 if not (sasl_agent or token_agent) then return; end | 35 if not (sasl_agent or token_agent) then return; end |
36 return { | 36 return { |
37 software = sasl_agent and sasl_agent.software or token_agent and token_agent.name or nil; | 37 software = sasl_agent and sasl_agent.software or token_agent and token_agent.name or nil; |
38 software_id = token_agent and token_agent.id or nil; | |
39 software_version = token_agent and token_agent.version or nil; | |
38 uri = token_agent and token_agent.uri or nil; | 40 uri = token_agent and token_agent.uri or nil; |
39 device = sasl_agent and sasl_agent.device or nil; | 41 device = sasl_agent and sasl_agent.device or nil; |
40 }; | 42 }; |
41 end | 43 end |
42 | 44 |
248 table.insert(active_clients, { | 250 table.insert(active_clients, { |
249 id = "grant/"..grant_id; | 251 id = "grant/"..grant_id; |
250 type = "access"; | 252 type = "access"; |
251 first_seen = grant.created; | 253 first_seen = grant.created; |
252 last_seen = grant.accessed; | 254 last_seen = grant.accessed; |
255 expires = grant.expires; | |
253 active = { | 256 active = { |
254 grant = grant; | 257 grant = grant; |
255 }; | 258 }; |
256 user_agent = get_user_agent(nil, grant); | 259 user_agent = get_user_agent(nil, grant); |
257 }); | 260 }); |
272 end | 275 end |
273 return a.id < b.id; | 276 return a.id < b.id; |
274 end); | 277 end); |
275 | 278 |
276 return active_clients; | 279 return active_clients; |
280 end | |
281 | |
282 local function user_agent_tostring(user_agent) | |
283 if user_agent then | |
284 if user_agent.software then | |
285 if user_agent.software_version then | |
286 return user_agent.software .. "/" .. user_agent.software_version; | |
287 end | |
288 return user_agent.software; | |
289 end | |
290 end | |
277 end | 291 end |
278 | 292 |
279 function revoke_client_access(username, client_selector) | 293 function revoke_client_access(username, client_selector) |
280 if client_selector then | 294 if client_selector then |
281 local c_type, c_id = client_selector:match("^(%w+)/(.+)$"); | 295 local c_type, c_id = client_selector:match("^(%w+)/(.+)$"); |
307 return nil, "item-not-found"; | 321 return nil, "item-not-found"; |
308 end | 322 end |
309 local ok = tokenauth.revoke_grant(username, c_id); | 323 local ok = tokenauth.revoke_grant(username, c_id); |
310 if not ok then return nil, "internal-server-error"; end | 324 if not ok then return nil, "internal-server-error"; end |
311 return true; | 325 return true; |
326 elseif c_type == "software" then | |
327 local active_clients = get_active_clients(username); | |
328 for _, client in ipairs(active_clients) do | |
329 if client.user_agent and client.user_agent.software == c_id or user_agent_tostring(client.user_agent) == c_id then | |
330 return revoke_client_access(username, client.id); | |
331 end | |
332 end | |
312 end | 333 end |
313 end | 334 end |
314 | 335 |
315 return nil, "item-not-found"; | 336 return nil, "item-not-found"; |
316 end | 337 end |
346 end | 367 end |
347 | 368 |
348 local user_agent = st.stanza("user-agent"); | 369 local user_agent = st.stanza("user-agent"); |
349 if client.user_agent then | 370 if client.user_agent then |
350 if client.user_agent.software then | 371 if client.user_agent.software then |
351 user_agent:text_tag("software", client.user_agent.software); | 372 user_agent:text_tag("software", client.user_agent.software, { id = client.user_agent.software_id; version = client.user_agent.software_version }); |
352 end | 373 end |
353 if client.user_agent.device then | 374 if client.user_agent.device then |
354 user_agent:text_tag("device", client.user_agent.device); | 375 user_agent:text_tag("device", client.user_agent.device); |
355 end | 376 end |
356 if client.user_agent.uri then | 377 if client.user_agent.uri then |
415 local clients = mod.get_active_clients(username); | 436 local clients = mod.get_active_clients(username); |
416 if not clients or #clients == 0 then | 437 if not clients or #clients == 0 then |
417 return true, "No clients associated with this account"; | 438 return true, "No clients associated with this account"; |
418 end | 439 end |
419 | 440 |
441 local function date_or_time(last_seen) | |
442 return last_seen and os.date(math.abs(os.difftime(os.time(), last_seen)) >= 86400 and "%Y-%m-%d" or "%H:%M:%S", last_seen); | |
443 end | |
444 | |
445 local date_or_time_width = math.max(#os.date("%Y-%m-%d"), #os.date("%H:%M:%S")); | |
446 | |
420 local colspec = { | 447 local colspec = { |
448 { title = "ID"; key = "id"; width = "1p" }; | |
421 { | 449 { |
422 title = "Software"; | 450 title = "Software"; |
423 key = "user_agent"; | 451 key = "user_agent"; |
424 width = "1p"; | 452 width = "1p"; |
425 mapper = function(user_agent) | 453 mapper = user_agent_tostring; |
426 return user_agent and user_agent.software; | 454 }; |
427 end; | 455 { |
456 title = "First seen"; | |
457 key = "first_seen"; | |
458 width = date_or_time_width; | |
459 align = "right"; | |
460 mapper = date_or_time; | |
428 }; | 461 }; |
429 { | 462 { |
430 title = "Last seen"; | 463 title = "Last seen"; |
431 key = "last_seen"; | 464 key = "last_seen"; |
432 width = math.max(#os.date("%Y-%m-%d"), #os.date("%H:%M:%S")); | 465 width = date_or_time_width; |
433 align = "right"; | 466 align = "right"; |
434 mapper = function(last_seen) | 467 mapper = date_or_time; |
435 return os.date(os.difftime(os.time(), last_seen) >= 86400 and "%Y-%m-%d" or "%H:%M:%S", last_seen); | 468 }; |
436 end; | 469 { |
470 title = "Expires"; | |
471 key = "expires"; | |
472 width = date_or_time_width; | |
473 align = "right"; | |
474 mapper = date_or_time; | |
437 }; | 475 }; |
438 { | 476 { |
439 title = "Authentication"; | 477 title = "Authentication"; |
440 key = "active"; | 478 key = "active"; |
441 width = "2p"; | 479 width = "2p"; |
454 print(row(client)); | 492 print(row(client)); |
455 end | 493 end |
456 print(string.rep("-", self.session.width)); | 494 print(string.rep("-", self.session.width)); |
457 return true, ("%d clients"):format(#clients); | 495 return true, ("%d clients"):format(#clients); |
458 end | 496 end |
497 | |
498 function console_env.user:revoke_client(user_jid, selector) -- luacheck: ignore 212/self | |
499 local username, host = jid.split(user_jid); | |
500 local mod = prosody.hosts[host] and prosody.hosts[host].modules.client_management; | |
501 if not mod then | |
502 return false, ("Host does not exist on this server, or does not have mod_client_management loaded"); | |
503 end | |
504 | |
505 local revoked, err = revocation_errors.coerce(mod.revoke_client_access(username, selector)); | |
506 if not revoked then | |
507 return false, err.text or err; | |
508 end | |
509 return true, "Client access revoked"; | |
510 end | |
459 end); | 511 end); |