index.uc 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright 2022 Jo-Philipp Wich <jo@mein.io>
  2. // Licensed to the public under the Apache License 2.0.
  3. import { load_catalog, change_catalog, get_translations } from 'luci.core';
  4. const ubus_types = [
  5. null,
  6. 'array',
  7. 'object',
  8. 'string',
  9. null, // INT64
  10. 'number',
  11. null, // INT16,
  12. 'boolean',
  13. 'double'
  14. ];
  15. function ubus_reply(id, data, code, errmsg) {
  16. const reply = { jsonrpc: '2.0', id };
  17. if (errmsg)
  18. reply.error = { code, message: errmsg };
  19. else if (type(code) == 'object')
  20. reply.result = code;
  21. else if (data != null)
  22. reply.result = [ code, data ];
  23. else
  24. reply.result = [ code ];
  25. return reply;
  26. }
  27. function ubus_access(sid, obj, fun) {
  28. return (ubus.call('session', 'access', {
  29. ubus_rpc_session: sid,
  30. scope: 'ubus',
  31. object: obj,
  32. function: fun
  33. })?.access == true);
  34. }
  35. function ubus_request(req) {
  36. if (type(req?.method) != 'string' || req?.jsonrpc != '2.0' || req?.id == null)
  37. return ubus_reply(null, null, -32600, 'Invalid request');
  38. if (req.method == 'call') {
  39. if (type(req?.params) != 'array' || length(req.params) < 3)
  40. return ubus_reply(null, null, -32600, 'Invalid parameters');
  41. let sid = req.params[0],
  42. obj = req.params[1],
  43. fun = req.params[2],
  44. arg = req.params[3] ?? {};
  45. if (type(arg) != 'object' || exists(arg, 'ubus_rpc_session'))
  46. return ubus_reply(req.id, null, -32602, 'Invalid parameters');
  47. if (sid == '00000000000000000000000000000000' && ctx.authsession)
  48. sid = ctx.authsession;
  49. if (!ubus_access(sid, obj, fun))
  50. return ubus_reply(req.id, null, -32002, 'Access denied');
  51. arg.ubus_rpc_session = sid;
  52. // clear error
  53. ubus.error();
  54. const res = ubus.call(obj, fun, arg);
  55. return ubus_reply(req.id, res, ubus.error(true) ?? 0);
  56. }
  57. if (req.method == 'list') {
  58. if (req?.params == null || (type(req.params) == 'array' && length(req.params) == 0)) {
  59. return ubus_reply(req.id, null, ubus.list());
  60. }
  61. else if (type(req.params) == 'array') {
  62. const rv = {};
  63. for (let param in req.params) {
  64. if (type(param) != 'string')
  65. return ubus_reply(req.id, null, -32602, 'Invalid parameters');
  66. for (let m, p in ubus.list(param)?.[0]) {
  67. for (let pn, pt in p) {
  68. rv[param] ??= {};
  69. rv[param][m] ??= {};
  70. rv[param][m][pn] = ubus_types[pt] ?? 'unknown';
  71. }
  72. }
  73. }
  74. return ubus_reply(req.id, null, rv);
  75. }
  76. else {
  77. return ubus_reply(req.id, null, -32602, 'Invalid parameters')
  78. }
  79. }
  80. return ubus_reply(req.id, null, -32601, 'Method not found')
  81. }
  82. return {
  83. action_ubus: function() {
  84. let request;
  85. try { request = json(http.content()); }
  86. catch { request = null; }
  87. http.prepare_content('application/json; charset=UTF-8');
  88. if (type(request) == 'object')
  89. http.write_json(ubus_request(request));
  90. else if (type(request) == 'array')
  91. http.write_json(map(request, ubus_request));
  92. else
  93. http.write_json(ubus_reply(null, null, -32700, 'Parse error'))
  94. },
  95. action_translations: function(reqlang) {
  96. if (reqlang != null && reqlang != dispatcher.lang) {
  97. load_catalog(reqlang, '/usr/lib/lua/luci/i18n');
  98. change_catalog(reqlang);
  99. }
  100. http.prepare_content('application/javascript; charset=UTF-8');
  101. http.write('window.TR={');
  102. get_translations((key, val) => http.write(sprintf('"%08x":%J,', key, val)));
  103. http.write('};');
  104. },
  105. action_logout: function() {
  106. const url = dispatcher.build_url();
  107. if (ctx.authsession) {
  108. ubus.call('session', 'destroy', { ubus_rpc_session: ctx.authsession });
  109. if (http.getenv('HTTPS') == 'on')
  110. http.header('Set-Cookie', `sysauth_https=; expires=Thu, 01 Jan 1970 01:00:00 GMT; path=${url}`);
  111. http.header('Set-Cookie', `sysauth_http=; expires=Thu, 01 Jan 1970 01:00:00 GMT; path=${url}`);
  112. }
  113. http.redirect(url);
  114. },
  115. action_menu: function() {
  116. const session = dispatcher.is_authenticated({ methods: [ 'cookie:sysauth_https', 'cookie:sysauth_http' ] });
  117. const menu = dispatcher.menu_json(session?.acls ?? {}) ?? {};
  118. http.prepare_content('application/json; charset=UTF-8');
  119. http.write_json(menu);
  120. }
  121. };