cmdbox 0.6.0.4__py3-none-any.whl → 0.6.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cmdbox might be problematic. Click here for more details.

Files changed (220) hide show
  1. cmdbox/app/app.py +2 -2
  2. cmdbox/app/auth/signin.py +144 -28
  3. cmdbox/app/common.py +40 -3
  4. cmdbox/app/edge.py +1 -1
  5. cmdbox/app/edge_tool.py +1 -1
  6. cmdbox/app/features/cli/agent_base.py +1 -335
  7. cmdbox/app/features/cli/cmdbox_audit_search.py +0 -2
  8. cmdbox/app/features/cli/cmdbox_audit_write.py +9 -0
  9. cmdbox/app/features/cli/cmdbox_cmd_list.py +1 -1
  10. cmdbox/app/features/cli/cmdbox_cmd_load.py +1 -1
  11. cmdbox/app/features/cli/cmdbox_mcp_proxy.py +90 -0
  12. cmdbox/app/features/cli/cmdbox_web_gencert.py +25 -2
  13. cmdbox/app/features/cli/cmdbox_web_start.py +4 -1
  14. cmdbox/app/features/web/cmdbox_web_signin.py +1 -1
  15. cmdbox/app/mcp.py +375 -0
  16. cmdbox/app/options.py +2 -0
  17. cmdbox/app/web.py +34 -6
  18. cmdbox/autoload.py +10 -0
  19. cmdbox/extensions/user_list.yml +25 -1
  20. cmdbox/licenses/{LICENSE.Deprecated.1.2.18(MIT License).txt → LICENSE_PyJWT_2_10_1_MIT_License.txt} +2 -2
  21. cmdbox/licenses/LICENSE_exceptiongroup_1_3_0_MIT_License.txt +73 -0
  22. cmdbox/licenses/LICENSE_fastmcp_2_9_2_Apache_Software_License.txt +201 -0
  23. cmdbox/licenses/{LICENSE.graphviz.0.20.3(MIT License).txt → LICENSE_graphviz_0_21_UNKNOWN.txt} +1 -1
  24. cmdbox/licenses/LICENSE_jaraco_functools_4_2_1_UNKNOWN.txt +18 -0
  25. cmdbox/licenses/{LICENSE.numpy.2.2.5(BSD License).txt → LICENSE_numpy_2_3_1_BSD_License.txt} +8 -8
  26. cmdbox/licenses/LICENSE_openapi-pydantic_0_5_1_MIT_License.txt +40 -0
  27. cmdbox/licenses/LICENSE_propcache_0_3_2_Apache_Software_License.txt +202 -0
  28. cmdbox/licenses/LICENSE_proto-plus_1_26_1_Apache_Software_License.txt +202 -0
  29. cmdbox/licenses/LICENSE_shellingham_1_5_4_ISC_License-ISCL.txt +13 -0
  30. cmdbox/licenses/LICENSE_sphinx-last-updated-by-git_0_3_8_BSD_License.txt +22 -0
  31. cmdbox/licenses/LICENSE_tenacity_8_5_0_Apache_Software_License.txt +202 -0
  32. cmdbox/licenses/LICENSE_tokenizers_0_21_2_Apache_Software_License.txt +1 -0
  33. cmdbox/licenses/LICENSE_typer_0_16_0_MIT_License.txt +21 -0
  34. cmdbox/licenses/LICENSE_typing-inspection_0_4_1_UNKNOWN.txt +21 -0
  35. cmdbox/licenses/LICENSE_yarl_1_20_1_Apache_Software_License.txt +202 -0
  36. cmdbox/licenses/LICENSE_zipp_3_23_0_UNKNOWN.txt +18 -0
  37. cmdbox/licenses/files.txt +176 -166
  38. cmdbox/logconf_mcp.yml +43 -0
  39. cmdbox/version.py +2 -2
  40. cmdbox/web/agent.html +1 -33
  41. cmdbox/web/assets/cmdbox/audit.js +1 -1
  42. cmdbox/web/assets/cmdbox/common.js +47 -4
  43. cmdbox/web/assets/cmdbox/svgicon.js +122 -0
  44. cmdbox/web/assets/cmdbox/users.js +4 -3
  45. cmdbox/web/audit.html +1 -35
  46. cmdbox/web/filer.html +1 -13
  47. cmdbox/web/gui.html +2 -50
  48. cmdbox/web/result.html +2 -46
  49. cmdbox/web/signin.html +1 -26
  50. cmdbox/web/users.html +1 -41
  51. {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.dist-info}/METADATA +31 -6
  52. cmdbox-0.6.1.dist-info/RECORD +383 -0
  53. cmdbox/licenses/LICENSE.keyring.25.6.0(MIT License).txt +0 -17
  54. cmdbox/licenses/LICENSE.typing-inspection.0.4.0(MIT License).txt +0 -21
  55. cmdbox/licenses/LICENSE.wrapt.1.17.2(BSD License).txt +0 -24
  56. cmdbox/licenses/LICENSE.zipp.3.21.0(MIT License).txt +0 -17
  57. cmdbox-0.6.0.4.dist-info/RECORD +0 -368
  58. /cmdbox/licenses/{LICENSE.Authlib.1.5.2(BSD License).txt → LICENSE_Authlib_1_6_0_BSD_License.txt} +0 -0
  59. /cmdbox/licenses/{LICENSE.Jinja2.3.1.6(BSD License).txt → LICENSE_Jinja2_3_1_6_BSD_License.txt} +0 -0
  60. /cmdbox/licenses/{LICENSE.MarkupSafe.3.0.2(BSD License).txt → LICENSE_MarkupSafe_3_0_2_BSD_License.txt} +0 -0
  61. /cmdbox/licenses/{LICENSE.PyYAML.6.0.2(MIT License).txt → LICENSE_PyYAML_6_0_2_MIT_License.txt} +0 -0
  62. /cmdbox/licenses/{LICENSE.Pygments.2.19.1(BSD License).txt → LICENSE_Pygments_2_19_2_BSD_License.txt} +0 -0
  63. /cmdbox/licenses/{LICENSE.SQLAlchemy.2.0.40(MIT License).txt → LICENSE_SQLAlchemy_2_0_41_MIT.txt} +0 -0
  64. /cmdbox/licenses/{LICENSE.Sphinx.8.2.3(UNKNOWN).txt → LICENSE_Sphinx_8_2_3_UNKNOWN.txt} +0 -0
  65. /cmdbox/licenses/{LICENSE.aiohappyeyeballs.2.6.1(Python Software Foundation License).txt → LICENSE_aiohappyeyeballs_2_6_1_Python_Software_Foundation_License.txt} +0 -0
  66. /cmdbox/licenses/{LICENSE.aiohttp.3.11.18(Apache Software License).txt → LICENSE_aiohttp_3_12_13_Apache-2_0.txt} +0 -0
  67. /cmdbox/licenses/{LICENSE.aiosignal.1.3.2(Apache Software License).txt → LICENSE_aiosignal_1_3_2_Apache_Software_License.txt} +0 -0
  68. /cmdbox/licenses/{LICENSE.alabaster.1.0.0(BSD License).txt → LICENSE_alabaster_1_0_0_BSD_License.txt} +0 -0
  69. /cmdbox/licenses/{LICENSE.annotated-types.0.7.0(MIT License).txt → LICENSE_annotated-types_0_7_0_MIT_License.txt} +0 -0
  70. /cmdbox/licenses/{LICENSE.anyio.4.9.0(MIT License).txt → LICENSE_anyio_4_9_0_MIT_License.txt} +0 -0
  71. /cmdbox/licenses/{LICENSE.argcomplete.3.6.2(Apache Software License).txt → LICENSE_argcomplete_3_6_2_Apache_Software_License.txt} +0 -0
  72. /cmdbox/licenses/{LICENSE.async-timeout.5.0.1(Apache Software License).txt → LICENSE_async-timeout_5_0_1_Apache_Software_License.txt} +0 -0
  73. /cmdbox/licenses/{LICENSE.attrs.25.3.0(UNKNOWN).txt → LICENSE_attrs_25_3_0_UNKNOWN.txt} +0 -0
  74. /cmdbox/licenses/{LICENSE.babel.2.17.0(BSD License).txt → LICENSE_babel_2_17_0_BSD_License.txt} +0 -0
  75. /cmdbox/licenses/{LICENSE.backports.tarfile.1.2.0(MIT License).txt → LICENSE_backports_tarfile_1_2_0_MIT_License.txt} +0 -0
  76. /cmdbox/licenses/{LICENSE.cachetools.5.5.2(MIT License).txt → LICENSE_cachetools_5_5_2_MIT_License.txt} +0 -0
  77. /cmdbox/licenses/{LICENSE.certifi.2025.4.26(Mozilla Public License 2.0 (MPL 2.0)).txt → LICENSE_certifi_2025_6_15_Mozilla_Public_License_2_0-MPL_2_0.txt} +0 -0
  78. /cmdbox/licenses/{LICENSE.cffi.1.17.1(MIT License).txt → LICENSE_cffi_1_17_1_MIT_License.txt} +0 -0
  79. /cmdbox/licenses/{LICENSE.charset-normalizer.3.4.2(MIT License).txt → LICENSE_charset-normalizer_3_4_2_MIT_License.txt} +0 -0
  80. /cmdbox/licenses/{LICENSE.click.8.2.0(UNKNOWN).txt → LICENSE_click_8_2_1_UNKNOWN.txt} +0 -0
  81. /cmdbox/licenses/{LICENSE.jiter.0.9.0(MIT License).txt → LICENSE_cloudpickle_3_1_1_BSD_License.txt} +0 -0
  82. /cmdbox/licenses/{LICENSE.colorama.0.4.6(BSD License).txt → LICENSE_colorama_0_4_6_BSD_License.txt} +0 -0
  83. /cmdbox/licenses/{LICENSE.cryptography.44.0.3(Apache Software License; BSD License).txt → LICENSE_cryptography_45_0_4_Apache-2_0_OR_BSD-3-Clause.txt} +0 -0
  84. /cmdbox/licenses/{LICENSE.distro.1.9.0(Apache Software License).txt → LICENSE_distro_1_9_0_Apache_Software_License.txt} +0 -0
  85. /cmdbox/licenses/{LICENSE.docstring_parser.0.16(MIT License).txt → LICENSE_docstring_parser_0_16_MIT_License.txt} +0 -0
  86. /cmdbox/licenses/{LICENSE.docutils.0.21.2(BSD License; GNU General Public License (GPL); Public Domain; Python Software Foundation License).txt → LICENSE_docutils_0_21_2_BSD_License-GNU_General_Public_License-GPL-Public_Domain-Python_Software_Foundation_License.txt} +0 -0
  87. /cmdbox/licenses/{LICENSE.fastapi.0.115.12(MIT License).txt → LICENSE_fastapi_0_115_14_MIT_License.txt} +0 -0
  88. /cmdbox/licenses/{LICENSE.filelock.3.18.0(The Unlicense (Unlicense)).txt → LICENSE_filelock_3_18_0_The_Unlicense-Unlicense.txt} +0 -0
  89. /cmdbox/licenses/{LICENSE.frozenlist.1.6.0(Apache-2.0).txt → LICENSE_frozenlist_1_7_0_Apache-2_0.txt} +0 -0
  90. /cmdbox/licenses/{LICENSE.fsspec.2025.3.2(BSD License).txt → LICENSE_fsspec_2025_5_1_BSD_License.txt} +0 -0
  91. /cmdbox/licenses/{LICENSE.gevent.25.4.2(MIT).txt → LICENSE_gevent_25_5_1_MIT.txt} +0 -0
  92. /cmdbox/licenses/{LICENSE.google-adk.0.5.0(Apache Software License).txt → LICENSE_google-adk_1_5_0_Apache_Software_License.txt} +0 -0
  93. /cmdbox/licenses/{LICENSE.google-api-core.2.24.2(Apache Software License).txt → LICENSE_google-api-core_2_25_1_Apache_Software_License.txt} +0 -0
  94. /cmdbox/licenses/{LICENSE.google-api-python-client.2.169.0(Apache Software License).txt → LICENSE_google-api-python-client_2_174_0_Apache_Software_License.txt} +0 -0
  95. /cmdbox/licenses/{LICENSE.google-auth-httplib2.0.2.0(Apache Software License).txt → LICENSE_google-auth-httplib2_0_2_0_Apache_Software_License.txt} +0 -0
  96. /cmdbox/licenses/{LICENSE.google-auth.2.40.1(Apache Software License).txt → LICENSE_google-auth_2_40_3_Apache_Software_License.txt} +0 -0
  97. /cmdbox/licenses/{LICENSE.google-cloud-aiplatform.1.92.0(Apache 2.0).txt → LICENSE_google-cloud-aiplatform_1_100_0_Apache_2_0.txt} +0 -0
  98. /cmdbox/licenses/{LICENSE.google-cloud-bigquery.3.31.0(Apache Software License).txt → LICENSE_google-cloud-appengine-logging_1_6_2_Apache_Software_License.txt} +0 -0
  99. /cmdbox/licenses/{LICENSE.google-cloud-core.2.4.3(Apache Software License).txt → LICENSE_google-cloud-audit-log_0_3_2_Apache_Software_License.txt} +0 -0
  100. /cmdbox/licenses/{LICENSE.google-cloud-resource-manager.1.14.2(Apache Software License).txt → LICENSE_google-cloud-bigquery_3_34_0_Apache_Software_License.txt} +0 -0
  101. /cmdbox/licenses/{LICENSE.google-cloud-secret-manager.2.23.3(Apache Software License).txt → LICENSE_google-cloud-core_2_4_3_Apache_Software_License.txt} +0 -0
  102. /cmdbox/licenses/{LICENSE.google-cloud-speech.2.32.0(Apache Software License).txt → LICENSE_google-cloud-logging_3_12_1_Apache_Software_License.txt} +0 -0
  103. /cmdbox/licenses/{LICENSE.google-cloud-storage.2.19.0(Apache Software License).txt → LICENSE_google-cloud-resource-manager_1_14_2_Apache_Software_License.txt} +0 -0
  104. /cmdbox/licenses/{LICENSE.google-cloud-trace.1.16.1(Apache Software License).txt → LICENSE_google-cloud-secret-manager_2_24_0_Apache_Software_License.txt} +0 -0
  105. /cmdbox/licenses/{LICENSE.google-crc32c.1.7.1(Apache 2.0).txt → LICENSE_google-cloud-speech_2_33_0_Apache_Software_License.txt} +0 -0
  106. /cmdbox/licenses/{LICENSE.google-genai.1.14.0(Apache Software License).txt → LICENSE_google-cloud-storage_2_19_0_Apache_Software_License.txt} +0 -0
  107. /cmdbox/licenses/{LICENSE.google-resumable-media.2.7.2(Apache Software License).txt → LICENSE_google-cloud-trace_1_16_2_Apache_Software_License.txt} +0 -0
  108. /cmdbox/licenses/{LICENSE.googleapis-common-protos.1.70.0(Apache Software License).txt → LICENSE_google-crc32c_1_7_1_Apache_2_0.txt} +0 -0
  109. /cmdbox/licenses/{LICENSE.grpc-google-iam-v1.0.14.2(Apache Software License).txt → LICENSE_google-genai_1_23_0_Apache_Software_License.txt} +0 -0
  110. /cmdbox/licenses/{LICENSE.id.1.5.0(Apache Software License).txt → LICENSE_google-resumable-media_2_7_2_Apache_Software_License.txt} +0 -0
  111. /cmdbox/licenses/{LICENSE.importlib_metadata.8.6.1(Apache Software License).txt → LICENSE_googleapis-common-protos_1_70_0_Apache_Software_License.txt} +0 -0
  112. /cmdbox/licenses/{LICENSE.greenlet.3.2.2(MIT AND Python-2.0).txt → LICENSE_greenlet_3_2_3_MIT_AND_Python-2_0.txt} +0 -0
  113. /cmdbox/licenses/{LICENSE.propcache.0.3.1(Apache Software License).txt → LICENSE_grpc-google-iam-v1_0_14_2_Apache_Software_License.txt} +0 -0
  114. /cmdbox/licenses/{LICENSE.grpcio-status.1.71.0(Apache Software License).txt → LICENSE_grpcio-status_1_73_1_Apache_Software_License.txt} +0 -0
  115. /cmdbox/licenses/{LICENSE.grpcio.1.71.0(Apache Software License).txt → LICENSE_grpcio_1_73_1_Apache_Software_License.txt} +0 -0
  116. /cmdbox/licenses/{LICENSE.gunicorn.23.0.0(MIT License).txt → LICENSE_gunicorn_23_0_0_MIT_License.txt} +0 -0
  117. /cmdbox/licenses/{LICENSE.h11.0.16.0(MIT License).txt → LICENSE_h11_0_16_0_MIT_License.txt} +0 -0
  118. /cmdbox/licenses/{LICENSE.httpcore.1.0.9(BSD License).txt → LICENSE_httpcore_1_0_9_BSD_License.txt} +0 -0
  119. /cmdbox/licenses/{LICENSE.httplib2.0.22.0(MIT License).txt → LICENSE_httplib2_0_22_0_MIT_License.txt} +0 -0
  120. /cmdbox/licenses/{LICENSE.httptools.0.6.4(MIT License).txt → LICENSE_httptools_0_6_4_MIT_License.txt} +0 -0
  121. /cmdbox/licenses/{LICENSE.httpx-sse.0.4.0(MIT).txt → LICENSE_httpx-sse_0_4_1_MIT.txt} +0 -0
  122. /cmdbox/licenses/{LICENSE.httpx.0.28.1(BSD License).txt → LICENSE_httpx_0_28_1_BSD_License.txt} +0 -0
  123. /cmdbox/licenses/{LICENSE.huggingface-hub.0.31.1(Apache Software License).txt → LICENSE_huggingface-hub_0_33_1_Apache_Software_License.txt} +0 -0
  124. /cmdbox/licenses/{LICENSE.proto-plus.1.26.1(Apache Software License).txt → LICENSE_id_1_5_0_Apache_Software_License.txt} +0 -0
  125. /cmdbox/licenses/{LICENSE.idna.3.10(BSD License).txt → LICENSE_idna_3_10_BSD_License.txt} +0 -0
  126. /cmdbox/licenses/{LICENSE.imagesize.1.4.1(MIT License).txt → LICENSE_imagesize_1_4_1_MIT_License.txt} +0 -0
  127. /cmdbox/licenses/{LICENSE.yarl.1.20.0(Apache Software License).txt → LICENSE_importlib_metadata_8_7_0_Apache_Software_License.txt} +0 -0
  128. /cmdbox/licenses/{LICENSE.itsdangerous.2.2.0(BSD License).txt → LICENSE_itsdangerous_2_2_0_BSD_License.txt} +0 -0
  129. /cmdbox/licenses/{LICENSE.jaraco.classes.3.4.0(MIT License).txt → LICENSE_jaraco_classes_3_4_0_MIT_License.txt} +0 -0
  130. /cmdbox/licenses/{LICENSE.jaraco.context.6.0.1(MIT License).txt → LICENSE_jaraco_context_6_0_1_MIT_License.txt} +0 -0
  131. /cmdbox/licenses/{LICENSE.sphinxcontrib-applehelp.2.0.0(BSD License).txt → LICENSE_jiter_0_10_0_MIT_License.txt} +0 -0
  132. /cmdbox/licenses/{LICENSE.jsonschema-specifications.2025.4.1(UNKNOWN).txt → LICENSE_jsonschema-specifications_2025_4_1_UNKNOWN.txt} +0 -0
  133. /cmdbox/licenses/{LICENSE.jsonschema.4.23.0(MIT License).txt → LICENSE_jsonschema_4_24_0_UNKNOWN.txt} +0 -0
  134. /cmdbox/licenses/{LICENSE.jaraco.functools.4.1.0(MIT License).txt → LICENSE_keyring_25_6_0_MIT_License.txt} +0 -0
  135. /cmdbox/licenses/{LICENSE.litellm.1.69.0(MIT License).txt → LICENSE_litellm_1_73_6_MIT_License.txt} +0 -0
  136. /cmdbox/licenses/{LICENSE.markdown-it-py.3.0.0(MIT License).txt → LICENSE_markdown-it-py_3_0_0_MIT_License.txt} +0 -0
  137. /cmdbox/licenses/{LICENSE.mcp.1.8.0(MIT License).txt → LICENSE_mcp_1_9_4_MIT_License.txt} +0 -0
  138. /cmdbox/licenses/{LICENSE.mdurl.0.1.2(MIT License).txt → LICENSE_mdurl_0_1_2_MIT_License.txt} +0 -0
  139. /cmdbox/licenses/{LICENSE.more-itertools.10.7.0(MIT License).txt → LICENSE_more-itertools_10_7_0_MIT_License.txt} +0 -0
  140. /cmdbox/licenses/{LICENSE.multidict.6.4.3(Apache Software License).txt → LICENSE_multidict_6_6_2_Apache_License_2_0.txt} +0 -0
  141. /cmdbox/licenses/{LICENSE.nh3.0.2.21(MIT).txt → LICENSE_nh3_0_2_21_MIT.txt} +0 -0
  142. /cmdbox/licenses/{LICENSE.openai.1.75.0(Apache Software License).txt → LICENSE_openai_1_93_0_Apache_Software_License.txt} +0 -0
  143. /cmdbox/licenses/{LICENSE.opentelemetry-api.1.33.0(Apache Software License).txt → LICENSE_opentelemetry-api_1_34_1_Apache_Software_License.txt} +0 -0
  144. /cmdbox/licenses/{LICENSE.opentelemetry-exporter-gcp-trace.1.9.0(Apache Software License).txt → LICENSE_opentelemetry-exporter-gcp-trace_1_9_0_Apache_Software_License.txt} +0 -0
  145. /cmdbox/licenses/{LICENSE.opentelemetry-resourcedetector-gcp.1.9.0a0(Apache Software License).txt → LICENSE_opentelemetry-resourcedetector-gcp_1_9_0a0_Apache_Software_License.txt} +0 -0
  146. /cmdbox/licenses/{LICENSE.opentelemetry-sdk.1.33.0(Apache Software License).txt → LICENSE_opentelemetry-sdk_1_34_1_Apache_Software_License.txt} +0 -0
  147. /cmdbox/licenses/{LICENSE.opentelemetry-semantic-conventions.0.54b0(Apache Software License).txt → LICENSE_opentelemetry-semantic-conventions_0_55b1_Apache_Software_License.txt} +0 -0
  148. /cmdbox/licenses/{LICENSE.packaging.25.0(Apache Software License; BSD License).txt → LICENSE_packaging_25_0_Apache_Software_License-BSD_License.txt} +0 -0
  149. /cmdbox/licenses/{LICENSE.pillow.11.2.1(UNKNOWN).txt → LICENSE_pillow_11_2_1_UNKNOWN.txt} +0 -0
  150. /cmdbox/licenses/{LICENSE.pip.24.0(MIT License).txt → LICENSE_pip_24_0_MIT_License.txt} +0 -0
  151. /cmdbox/licenses/{LICENSE.plyer.2.1.0(MIT License).txt → LICENSE_plyer_2_1_0_MIT_License.txt} +0 -0
  152. /cmdbox/licenses/{LICENSE.prettytable.3.16.0(UNKNOWN).txt → LICENSE_prettytable_3_16_0_UNKNOWN.txt} +0 -0
  153. /cmdbox/licenses/{LICENSE.prompt_toolkit.3.0.51(BSD License).txt → LICENSE_prompt_toolkit_3_0_51_BSD_License.txt} +0 -0
  154. /cmdbox/licenses/{LICENSE.protobuf.5.29.4(3-Clause BSD License).txt → LICENSE_protobuf_6_31_1_3-Clause_BSD_License.txt} +0 -0
  155. /cmdbox/licenses/{LICENSE.psycopg-binary.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE_psycopg-binary_3_2_9_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
  156. /cmdbox/licenses/{LICENSE.psycopg.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE_psycopg_3_2_9_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
  157. /cmdbox/licenses/{LICENSE.pyasn1.0.6.1(BSD License).txt → LICENSE_pyasn1_0_6_1_BSD_License.txt} +0 -0
  158. /cmdbox/licenses/{LICENSE.pyasn1_modules.0.4.2(BSD License).txt → LICENSE_pyasn1_modules_0_4_2_BSD_License.txt} +0 -0
  159. /cmdbox/licenses/{LICENSE.pycparser.2.22(BSD License).txt → LICENSE_pycparser_2_22_BSD_License.txt} +0 -0
  160. /cmdbox/licenses/{LICENSE.pycryptodome.3.22.0(BSD License; Public Domain).txt → LICENSE_pycryptodome_3_23_0_BSD_License-Public_Domain.txt} +0 -0
  161. /cmdbox/licenses/{LICENSE.pydantic-settings.2.9.1(MIT License).txt → LICENSE_pydantic-settings_2_10_1_MIT_License.txt} +0 -0
  162. /cmdbox/licenses/{LICENSE.pydantic.2.11.4(MIT License).txt → LICENSE_pydantic_2_11_7_MIT_License.txt} +0 -0
  163. /cmdbox/licenses/{LICENSE.pydantic_core.2.33.2(MIT License).txt → LICENSE_pydantic_core_2_33_2_MIT_License.txt} +0 -0
  164. /cmdbox/licenses/{LICENSE.pyparsing.3.2.3(MIT License).txt → LICENSE_pyparsing_3_2_3_MIT_License.txt} +0 -0
  165. /cmdbox/licenses/{LICENSE.pystray.0.19.5(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE_pystray_0_19_5_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
  166. /cmdbox/licenses/{LICENSE.python-dateutil.2.9.0.post0(Apache Software License; BSD License).txt → LICENSE_python-dateutil_2_9_0_post0_Apache_Software_License-BSD_License.txt} +0 -0
  167. /cmdbox/licenses/{LICENSE.python-dotenv.1.1.0(BSD License).txt → LICENSE_python-dotenv_1_1_1_BSD_License.txt} +0 -0
  168. /cmdbox/licenses/{LICENSE.python-multipart.0.0.20(Apache Software License).txt → LICENSE_python-multipart_0_0_20_Apache_Software_License.txt} +0 -0
  169. /cmdbox/licenses/{LICENSE.pywin32-ctypes.0.2.3(BSD-3-Clause).txt → LICENSE_pywin32-ctypes_0_2_3_BSD-3-Clause.txt} +0 -0
  170. /cmdbox/licenses/{LICENSE.questionary.2.1.0(MIT License).txt → LICENSE_questionary_2_1_0_MIT_License.txt} +0 -0
  171. /cmdbox/licenses/{LICENSE.readme_renderer.44.0(Apache Software License).txt → LICENSE_readme_renderer_44_0_Apache_Software_License.txt} +0 -0
  172. /cmdbox/licenses/{LICENSE.redis.6.0.0(MIT License).txt → LICENSE_redis_6_2_0_MIT_License.txt} +0 -0
  173. /cmdbox/licenses/{LICENSE.referencing.0.36.2(UNKNOWN).txt → LICENSE_referencing_0_36_2_UNKNOWN.txt} +0 -0
  174. /cmdbox/licenses/{LICENSE.regex.2024.11.6(Apache Software License).txt → LICENSE_regex_2024_11_6_Apache_Software_License.txt} +0 -0
  175. /cmdbox/licenses/{LICENSE.requests-toolbelt.1.0.0(Apache Software License).txt → LICENSE_requests-toolbelt_1_0_0_Apache_Software_License.txt} +0 -0
  176. /cmdbox/licenses/{LICENSE.requests.2.32.3(Apache Software License).txt → LICENSE_requests_2_32_4_Apache_Software_License.txt} +0 -0
  177. /cmdbox/licenses/{LICENSE.rfc3986.2.0.0(Apache Software License).txt → LICENSE_rfc3986_2_0_0_Apache_Software_License.txt} +0 -0
  178. /cmdbox/licenses/{LICENSE.rich.14.0.0(MIT License).txt → LICENSE_rich_14_0_0_MIT_License.txt} +0 -0
  179. /cmdbox/licenses/{LICENSE.roman-numerals-py.3.1.0(CC0 1.0 Universal (CC0 1.0) Public Domain Dedication; Zero-Clause BSD (0BSD)).txt → LICENSE_roman-numerals-py_3_1_0_CC0_1_0_Universal-CC0_1_0-Public_Domain_Dedication-Zero-Clause_BSD-0BSD.txt} +0 -0
  180. /cmdbox/licenses/{LICENSE.rpds-py.0.24.0(MIT).txt → LICENSE_rpds-py_0_25_1_MIT.txt} +0 -0
  181. /cmdbox/licenses/{LICENSE.rsa.4.9.1(Apache Software License).txt → LICENSE_rsa_4_9_1_Apache_Software_License.txt} +0 -0
  182. /cmdbox/licenses/{LICENSE.setuptools.65.5.0(MIT License).txt → LICENSE_setuptools_65_5_0_MIT_License.txt} +0 -0
  183. /cmdbox/licenses/{LICENSE.shapely.2.1.0(BSD License).txt → LICENSE_shapely_2_1_1_BSD_License.txt} +0 -0
  184. /cmdbox/licenses/{LICENSE.six.1.17.0(MIT License).txt → LICENSE_six_1_17_0_MIT_License.txt} +0 -0
  185. /cmdbox/licenses/{LICENSE.sniffio.1.3.1(Apache Software License; MIT License).txt → LICENSE_sniffio_1_3_1_Apache_Software_License-MIT_License.txt} +0 -0
  186. /cmdbox/licenses/{LICENSE.snowballstemmer.3.0.1(BSD License).txt → LICENSE_snowballstemmer_3_0_1_BSD_License.txt} +0 -0
  187. /cmdbox/licenses/{LICENSE.sphinx-intl.2.3.1(BSD License).txt → LICENSE_sphinx-intl_2_3_1_BSD_License.txt} +0 -0
  188. /cmdbox/licenses/{LICENSE.sphinx-rtd-theme.3.0.2(MIT License).txt → LICENSE_sphinx-rtd-theme_3_0_2_MIT_License.txt} +0 -0
  189. /cmdbox/licenses/{LICENSE.sphinx-sitemap.2.6.0(MIT License).txt → LICENSE_sphinx-sitemap_2_7_2_UNKNOWN.txt} +0 -0
  190. /cmdbox/licenses/{LICENSE.sphinx_fontawesome.0.0.6(GNU General Public License v2 (GPLv2)).txt → LICENSE_sphinx_fontawesome_0_0_6_GNU_General_Public_License_v2-GPLv2.txt} +0 -0
  191. /cmdbox/licenses/{LICENSE.sphinxcontrib-devhelp.2.0.0(BSD License).txt → LICENSE_sphinxcontrib-applehelp_2_0_0_BSD_License.txt} +0 -0
  192. /cmdbox/licenses/{LICENSE.sphinxcontrib-htmlhelp.2.1.0(BSD License).txt → LICENSE_sphinxcontrib-devhelp_2_0_0_BSD_License.txt} +0 -0
  193. /cmdbox/licenses/{LICENSE.sphinxcontrib-jquery.4.1(BSD License).txt → LICENSE_sphinxcontrib-htmlhelp_2_1_0_BSD_License.txt} +0 -0
  194. /cmdbox/licenses/{LICENSE.sphinxcontrib-qthelp.2.0.0(BSD License).txt → LICENSE_sphinxcontrib-jquery_4_1_BSD_License.txt} +0 -0
  195. /cmdbox/licenses/{LICENSE.sphinxcontrib-jsmath.1.0.1(BSD License).txt → LICENSE_sphinxcontrib-jsmath_1_0_1_BSD_License.txt} +0 -0
  196. /cmdbox/licenses/{LICENSE.sphinxcontrib-serializinghtml.2.0.0(BSD License).txt → LICENSE_sphinxcontrib-qthelp_2_0_0_BSD_License.txt} +0 -0
  197. /cmdbox/licenses/{LICENSE.tokenizers.0.21.1(Apache Software License).txt → LICENSE_sphinxcontrib-serializinghtml_2_0_0_BSD_License.txt} +0 -0
  198. /cmdbox/licenses/{LICENSE.sse-starlette.2.3.4(BSD License).txt → LICENSE_sse-starlette_2_3_6_BSD_License.txt} +0 -0
  199. /cmdbox/licenses/{LICENSE.starlette.0.46.2(BSD License).txt → LICENSE_starlette_0_46_2_BSD_License.txt} +0 -0
  200. /cmdbox/licenses/{LICENSE.tabulate.0.9.0(MIT License).txt → LICENSE_tabulate_0_9_0_MIT_License.txt} +0 -0
  201. /cmdbox/licenses/{LICENSE.tiktoken.0.9.0(MIT License).txt → LICENSE_tiktoken_0_9_0_MIT_License-Copyright-c-2022_OpenAI-Shantanu_Jain-Permission_is_hereby_granted-free_of_charge-to_any_pers.txt} +0 -0
  202. /cmdbox/licenses/{LICENSE.tomli.2.2.1(MIT License).txt → LICENSE_tomli_2_2_1_MIT_License.txt} +0 -0
  203. /cmdbox/licenses/{LICENSE.tqdm.4.67.1(MIT License; Mozilla Public License 2.0 (MPL 2.0)).txt → LICENSE_tqdm_4_67_1_MIT_License-Mozilla_Public_License_2_0-MPL_2_0.txt} +0 -0
  204. /cmdbox/licenses/{LICENSE.twine.6.1.0(Apache Software License).txt → LICENSE_twine_6_1_0_Apache_Software_License.txt} +0 -0
  205. /cmdbox/licenses/{LICENSE.typing_extensions.4.13.2(UNKNOWN).txt → LICENSE_typing_extensions_4_14_0_UNKNOWN.txt} +0 -0
  206. /cmdbox/licenses/{LICENSE.tzdata.2025.2(Apache Software License).txt → LICENSE_tzdata_2025_2_Apache_Software_License.txt} +0 -0
  207. /cmdbox/licenses/{LICENSE.tzlocal.5.3.1(MIT License).txt → LICENSE_tzlocal_5_3_1_MIT_License.txt} +0 -0
  208. /cmdbox/licenses/{LICENSE.uritemplate.4.1.1(Apache Software License; BSD License).txt → LICENSE_uritemplate_4_2_0_BSD_3-Clause_OR_Apache-2_0.txt} +0 -0
  209. /cmdbox/licenses/{LICENSE.urllib3.2.4.0(UNKNOWN).txt → LICENSE_urllib3_2_5_0_UNKNOWN.txt} +0 -0
  210. /cmdbox/licenses/{LICENSE.uvicorn.0.34.2(BSD License).txt → LICENSE_uvicorn_0_35_0_BSD_License.txt} +0 -0
  211. /cmdbox/licenses/{LICENSE.watchfiles.1.0.5(MIT License).txt → LICENSE_watchfiles_1_1_0_MIT_License.txt} +0 -0
  212. /cmdbox/licenses/{LICENSE.wcwidth.0.2.13(MIT License).txt → LICENSE_wcwidth_0_2_13_MIT_License.txt} +0 -0
  213. /cmdbox/licenses/{LICENSE.websockets.15.0.1(BSD License).txt → LICENSE_websockets_15_0_1_BSD_License.txt} +0 -0
  214. /cmdbox/licenses/{LICENSE.wheel.0.45.1(MIT License).txt → LICENSE_wheel_0_45_1_MIT_License.txt} +0 -0
  215. /cmdbox/licenses/{LICENSE.zope.event.5.0(Zope Public License).txt → LICENSE_zope_event_5_1_Zope_Public_License.txt} +0 -0
  216. /cmdbox/licenses/{LICENSE.zope.interface.7.2(Zope Public License).txt → LICENSE_zope_interface_7_2_Zope_Public_License.txt} +0 -0
  217. {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.dist-info}/LICENSE +0 -0
  218. {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.dist-info}/WHEEL +0 -0
  219. {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.dist-info}/entry_points.txt +0 -0
  220. {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.dist-info}/top_level.txt +0 -0
cmdbox/app/app.py CHANGED
@@ -9,9 +9,9 @@ import time
9
9
  import sys
10
10
 
11
11
 
12
- def main(args_list:list=None):
12
+ def main(args_list:list=None, webcall:bool=False):
13
13
  app = CmdBoxApp.getInstance(appcls=CmdBoxApp, ver=version)
14
- return app.main(args_list)[0]
14
+ return app.main(args_list, webcall=webcall)[0]
15
15
 
16
16
  class CmdBoxApp:
17
17
  _instance = None
cmdbox/app/auth/signin.py CHANGED
@@ -1,11 +1,16 @@
1
1
  from cmdbox.app import common, options
2
+ from cryptography import x509
3
+ from cryptography.hazmat.primitives import serialization
4
+ from cryptography.hazmat.backends import default_backend
2
5
  from fastapi import Request, Response, HTTPException, WebSocket
3
6
  from fastapi.responses import RedirectResponse
4
7
  from pathlib import Path
5
8
  from typing import Dict, Any, Tuple, List, Union
9
+ import argparse
6
10
  import copy
7
11
  import contextvars
8
12
  import logging
13
+ import jwt
9
14
  import string
10
15
 
11
16
 
@@ -87,7 +92,7 @@ class Signin(object):
87
92
  if self.signin_file_data is None:
88
93
  return None
89
94
  if 'signin' in req.session:
90
- self.signin_file_data = Signin.load_signin_file(self.signin_file, self.signin_file_data) # サインインファイルの更新をチェック
95
+ self.signin_file_data = Signin.load_signin_file(self.signin_file, self.signin_file_data, self=self) # サインインファイルの更新をチェック
91
96
  return Signin._check_signin(req, res, self.signin_file_data, self.logger)
92
97
 
93
98
  @classmethod
@@ -157,17 +162,37 @@ class Signin(object):
157
162
  if not auth.startswith('Bearer '):
158
163
  #self.logger.warning(f"Bearer not found. headers={req.headers}")
159
164
  return RedirectResponse(url=f'/signin{req.url.path}?error=apikeyfail')
160
- bearer, apikey = auth.split(' ')
161
- apikey = common.hash_password(apikey.strip(), 'sha1')
165
+ bearer, apikey = auth.split(' ').strip()
162
166
  if logger.level == logging.DEBUG:
163
- logger.debug(f"hashed apikey: {apikey}")
167
+ logger.debug(f"received apikey: {apikey}")
164
168
  find_user = None
169
+ jwt_enabled = signin_file_data['apikey']['verify_jwt']['enabled']
165
170
  for user in signin_file_data['users']:
166
171
  if 'apikeys' not in user:
167
172
  continue
168
173
  for ak, key in user['apikeys'].items():
169
174
  if apikey == key:
170
- find_user = user
175
+ if jwt_enabled:
176
+ publickey = None
177
+ if hasattr(cls, 'verify_jwt_certificate') and cls.verify_jwt_certificate is not None:
178
+ publickey = cls.verify_jwt_certificate.public_key()
179
+ if hasattr(cls, 'verify_jwt_publickey') and cls.verify_jwt_publickey is not None:
180
+ publickey = cls.verify_jwt_publickey
181
+ algorithm = signin_file_data['apikey']['verify_jwt']['algorithm']
182
+ issuer = signin_file_data['apikey']['verify_jwt']['issuer']
183
+ audience = signin_file_data['apikey']['verify_jwt']['audience']
184
+ claims = jwt.decode(apikey, publickey, algorithms=[algorithm],
185
+ issuer=issuer, audience=audience,
186
+ options={'verify_iss': issuer is not None,
187
+ 'verify_aud': audience is not None},)
188
+ find_user = dict(**claims, **user)
189
+ find_user['uid'] = find_user['uid'] if 'uid' in find_user else -1
190
+ find_user['name'] = find_user['name'] if 'name' in find_user else None
191
+ find_user['groups'] = find_user['groups'] if 'groups' in find_user else None
192
+ find_user['email'] = find_user['email'] if 'email' in find_user else None
193
+ find_user['apikey_name'] = find_user['apikey_name'] if 'apikey_name' in find_user else None
194
+ else:
195
+ find_user = user
171
196
  if find_user is None:
172
197
  logger.warning(f"No matching user found for apikey.")
173
198
  return RedirectResponse(url=f'/signin{req.url.path}?error=apikeyfail')
@@ -196,7 +221,22 @@ class Signin(object):
196
221
  return RedirectResponse(url=f'/signin{req.url.path}?error=unauthorizedsite')
197
222
 
198
223
  @classmethod
199
- def load_signin_file(cls, signin_file:Path, signin_file_data:Dict[str, Any]=None) -> Dict[str, Any]:
224
+ def load_pem_private_key(cls, data:bytes, passphrase:str=None):
225
+ return serialization.load_pem_private_key(
226
+ data,
227
+ password=passphrase.encode('utf-8') if passphrase else None,
228
+ backend=default_backend())
229
+
230
+ @classmethod
231
+ def load_pem_public_key(cls, data:bytes):
232
+ return serialization.load_pem_public_key(data, backend=default_backend())
233
+
234
+ @classmethod
235
+ def load_pem_x509_certificate(cls, data:bytes):
236
+ return x509.load_pem_x509_certificate(data, backend=default_backend())
237
+
238
+ @classmethod
239
+ def load_signin_file(cls, signin_file:Path, signin_file_data:Dict[str, Any]=None, self=None) -> Dict[str, Any]:
200
240
  """
201
241
  サインインファイルを読み込む
202
242
 
@@ -390,6 +430,90 @@ class Signin(object):
390
430
  raise HTTPException(status_code=500, detail=f'signin_file format error. "reset" not found in "password.lockout". ({signin_file})')
391
431
  if type(yml['password']['lockout']['reset']) is not int:
392
432
  raise HTTPException(status_code=500, detail=f'signin_file format error. "reset" not int type in "password.lockout". ({signin_file})')
433
+ # apikeyのフォーマットチェック
434
+ if 'apikey' not in yml:
435
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "apikey" not found. ({signin_file})')
436
+ if 'gen_cert' not in yml['apikey']:
437
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "gen_cert" not found in "apikey". ({signin_file})')
438
+ if 'enabled' not in yml['apikey']['gen_cert']:
439
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "enabled" not found in "apikey.gen_cert". ({signin_file})')
440
+ if type(yml['apikey']['gen_cert']['enabled']) is not bool:
441
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "enabled" not bool type in "apikey.gen_cert". ({signin_file})')
442
+ if yml['apikey']['gen_cert']['enabled']:
443
+ if 'privatekey' not in yml['apikey']['gen_cert']:
444
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "privatekey" not found in "apikey.gen_cert". ({signin_file})')
445
+ if 'certificate' not in yml['apikey']['gen_cert']:
446
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "certificate" not found in "apikey.gen_cert". ({signin_file})')
447
+ if 'publickey' not in yml['apikey']['gen_cert']:
448
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "publickey" not found in "apikey.gen_cert". ({signin_file})')
449
+ if not Path(yml['apikey']['gen_cert']['certificate']).is_file():
450
+ from cmdbox.app.features.cli.cmdbox_web_gencert import WebGencert
451
+ gencert = WebGencert(self.appcls, self.ver)
452
+ opt = dict(webhost=self.ver.__appid__, overwrite=True,
453
+ output_cert=yml['apikey']['gen_cert']['certificate'], output_cert_format='PEM',
454
+ output_pkey=yml['apikey']['gen_cert']['publickey'], output_pkey_format='PEM',
455
+ output_key=yml['apikey']['gen_cert']['privatekey'], output_key_format='PEM',)
456
+ args = argparse.Namespace(**opt)
457
+ status, res, _ = gencert.apprun(self.logger, args, 0, [])
458
+ if status != 0:
459
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "gen_cert" generate error in "apikey.gen_cert". ({signin_file}) {res}')
460
+ if 'gen_jwt' not in yml['apikey']:
461
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "gen_jwt" not found in "apikey". ({signin_file})')
462
+ if 'enabled' not in yml['apikey']['gen_jwt']:
463
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "enabled" not found in "apikey.gen_jwt". ({signin_file})')
464
+ if type(yml['apikey']['gen_jwt']['enabled']) is not bool:
465
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "enabled" not bool type in "apikey.gen_jwt". ({signin_file})')
466
+ if yml['apikey']['gen_jwt']['enabled']:
467
+ if 'privatekey' not in yml['apikey']['gen_jwt']:
468
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "privatekey" not found in "apikey.gen_jwt". ({signin_file})')
469
+ if 'privatekey_passphrase' not in yml['apikey']['gen_jwt']:
470
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "privatekey_passphrase" not found in "apikey.gen_jwt". ({signin_file})')
471
+ if not Path(yml['apikey']['gen_jwt']['privatekey']).is_file():
472
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "privatekey" file not found in "apikey.gen_jwt". ({signin_file})')
473
+ with open(yml['apikey']['gen_jwt']['privatekey'], 'rb') as f:
474
+ cls.gen_jwt_privatekey = cls.load_pem_private_key(f.read(), yml['apikey']['gen_jwt'].get('privatekey_passphrase', None))
475
+ if 'algorithm' not in yml['apikey']['gen_jwt']:
476
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "algorithm" not found in "apikey.gen_jwt". ({signin_file})')
477
+ cls.gen_jwt_algorithm = yml['apikey']['gen_jwt']['algorithm']
478
+ if 'claims' not in yml['apikey']['gen_jwt']:
479
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "claims" not found in "apikey.gen_jwt". ({signin_file})')
480
+ cls.gen_jwt_claims = yml['apikey']['gen_jwt']['claims'].copy()
481
+ if type(yml['apikey']['gen_jwt']['claims']) is not dict:
482
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "claims" not dict type in "apikey.gen_jwt". ({signin_file})')
483
+ if 'verify_jwt' not in yml['apikey']:
484
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "verify_jwt" not found in "apikey". ({signin_file})')
485
+ if 'enabled' not in yml['apikey']['verify_jwt']:
486
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "enabled" not found in "apikey.verify_jwt". ({signin_file})')
487
+ if type(yml['apikey']['verify_jwt']['enabled']) is not bool:
488
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "enabled" not bool type in "apikey.verify_jwt". ({signin_file})')
489
+ if yml['apikey']['verify_jwt']['enabled']:
490
+ if 'certificate' not in yml['apikey']['verify_jwt']:
491
+ if 'publickey' not in yml['apikey']['verify_jwt']:
492
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "certificate" or "publickey" not found in "apikey.verify_jwt". ({signin_file})')
493
+ if not Path(yml['apikey']['verify_jwt']['publickey']).is_file():
494
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "publickey" file not found in "apikey.verify_jwt". ({signin_file})')
495
+ with open(yml['apikey']['verify_jwt']['publickey'], 'rb') as f:
496
+ cls.verify_jwt_publickey_str = f.read()
497
+ cls.verify_jwt_publickey = cls.load_pem_public_key(cls.verify_jwt_publickey_str)
498
+ cls.verify_jwt_publickey_str = cls.verify_jwt_publickey_str.decode('utf-8')
499
+ else:
500
+ if not Path(yml['apikey']['verify_jwt']['certificate']).is_file():
501
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "certificate" file not found in "apikey.verify_jwt". ({signin_file})')
502
+ with open(yml['apikey']['verify_jwt']['certificate'], 'rb') as f:
503
+ cls.verify_jwt_certificate = cls.load_pem_x509_certificate(f.read())
504
+ cls.verify_jwt_publickey = cls.verify_jwt_certificate.public_key()
505
+ cls.verify_jwt_publickey_str = cls.verify_jwt_publickey.public_bytes(
506
+ encoding=serialization.Encoding.PEM,
507
+ format=serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
508
+ if 'issuer' not in yml['apikey']['verify_jwt']:
509
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "issuer" not found in "apikey.verify_jwt". ({signin_file})')
510
+ cls.verify_jwt_issuer = yml['apikey']['verify_jwt']['issuer']
511
+ if 'audience' not in yml['apikey']['verify_jwt']:
512
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "audience" not found in "apikey.verify_jwt". ({signin_file})')
513
+ cls.verify_jwt_audience = yml['apikey']['verify_jwt']['audience']
514
+ if 'algorithm' not in yml['apikey']['verify_jwt']:
515
+ raise HTTPException(status_code=500, detail=f'signin_file format error. "algorithm" not found in "apikey.verify_jwt". ({signin_file})')
516
+ cls.verify_jwt_algorithm = yml['apikey']['verify_jwt']['algorithm']
393
517
  # oauth2のフォーマットチェック
394
518
  if 'oauth2' not in yml:
395
519
  raise HTTPException(status_code=500, detail=f'signin_file format error. "oauth2" not found. ({signin_file})')
@@ -485,7 +609,7 @@ class Signin(object):
485
609
  group_names (List[str]): グループ名リスト
486
610
  master_groups (List[Dict[str, Any]], optional): 親グループ名. Defaults to None.
487
611
  """
488
- copy_signin_data = copy.deepcopy(signin_file_data)
612
+ copy_signin_data = copy.deepcopy(dict(groups=signin_file_data['groups']))
489
613
  master_groups = copy_signin_data['groups'] if master_groups is None else master_groups
490
614
  gns = []
491
615
  for gn in group_names.copy():
@@ -788,16 +912,12 @@ async def create_request_scope(req:Request=None, res:Response=None, websocket:We
788
912
  これは、FastAPIのDependsで使用されることを意図しています。
789
913
  次のように使用します。
790
914
 
791
- Example:
792
-
793
- ::
915
+ from cmdbox.app.auth import signin
916
+ from fastapi import Depends, Request, Response
794
917
 
795
- from cmdbox.app.auth import signin
796
- from fastapi import Depends, Request, Response
797
-
798
- @app.get("/some-endpoint")
799
- async def some_endpoint(req: Request, res: Response, scope=Depends(signin.create_request_scope)):
800
- # 何らかの処理
918
+ @app.get("/some-endpoint")
919
+ async def some_endpoint(req: Request, res: Response, scope=Depends(signin.create_request_scope)):
920
+ pass
801
921
 
802
922
  Args:
803
923
  req (Request): リクエスト
@@ -818,18 +938,14 @@ def get_request_scope() -> Dict[str, Any]:
818
938
  """
819
939
  FastAPIのDepends用に、ContextVarからリクエストスコープを取得します。
820
940
 
821
- Example:
822
-
823
- ::
824
-
825
- from cmdbox.app.auth import signin
826
- from fastapi import Request, Response
827
- scope = signin.get_request_scope()
828
- scope['req'] # Requestオブジェクト
829
- scope['res'] # Responseオブジェクト
830
- scope['session'] # sessionを表す辞書
831
- scope['websocket'] # WebSocket接続
832
- scope['logger'] # loggerオブジェクト
941
+ from cmdbox.app.auth import signin
942
+ from fastapi import Request, Response
943
+ scope = signin.get_request_scope()
944
+ scope['req'] # Requestオブジェクト
945
+ scope['res'] # Responseオブジェクト
946
+ scope['session'] # sessionを表す辞書
947
+ scope['websocket'] # WebSocket接続
948
+ scope['logger'] # loggerオブジェクト
833
949
 
834
950
  Returns:
835
951
  Dict[str, Any]: リクエストとレスポンスとWebSocket接続
cmdbox/app/common.py CHANGED
@@ -93,7 +93,33 @@ def save_yml(yml_path:Path, data:dict) -> None:
93
93
  with open(yml_path, 'w') as f:
94
94
  yaml.dump(data, f, default_flow_style=False, sort_keys=False)
95
95
 
96
- def reset_logger(name:str, stderr:bool=False, fmt:str='[%(asctime)s] %(levelname)s - %(message)s', datefmt:str='%Y-%m-%d %H:%M:%S') -> None:
96
+ class CommonValue:
97
+ _map = dict()
98
+
99
+ def set_common_value(key:str, value:Any) -> None:
100
+ """
101
+ 共通の値を設定します。
102
+
103
+ Args:
104
+ key (str): キー
105
+ value (Any): 値
106
+ """
107
+ CommonValue._map[key] = value
108
+
109
+ def get_common_value(key:str, default:Any=None) -> Any:
110
+ """
111
+ 共通の値を取得します。
112
+
113
+ Args:
114
+ key (str): キー
115
+ default (Any, optional): デフォルト値. Defaults to None.
116
+
117
+ Returns:
118
+ Any: 取得した値。存在しない場合はdefault値を返します。
119
+ """
120
+ return CommonValue._map.get(key, default)
121
+
122
+ def reset_logger(name:str, stderr:bool=False, fmt:str='[%(asctime)s] %(levelname)s - %(message)s', datefmt:str='%Y-%m-%d %H:%M:%S', level:int=logging.INFO) -> None:
97
123
  """
98
124
  指定されたロガーのハンドラをクリアし、新しいハンドラを追加します。
99
125
  Args:
@@ -101,13 +127,21 @@ def reset_logger(name:str, stderr:bool=False, fmt:str='[%(asctime)s] %(levelname
101
127
  stderr (bool, optional): 標準エラー出力を使用するかどうか. Defaults to False.
102
128
  fmt (str, optional): ログフォーマット. Defaults to '[%(asctime)s] %(levelname)s - %(message)s'.
103
129
  datefmt (str, optional): 日時フォーマット. Defaults to '%Y-%m-%d %H:%M:%S'.
130
+ level (int, optional): ログレベル. Defaults to logging.INFO.
104
131
  """
105
132
  logger = logging.getLogger(name)
106
133
  logger.handlers.clear()
107
134
  logger.propagate = False
108
- logger.addHandler(create_log_handler(stderr, fmt, datefmt))
135
+ logger.setLevel(level)
136
+ logger.addHandler(create_log_handler(stderr, fmt, datefmt, level))
137
+ if get_common_value('webcall', False):
138
+ # webcallの場合はStreamHandlerを削除
139
+ for handler in logger.handlers:
140
+ hc = handler.__class__
141
+ if issubclass(hc, logging.StreamHandler) and not issubclass(hc, logging.FileHandler):
142
+ logger.removeHandler(handler)
109
143
 
110
- def create_log_handler(stderr:bool=False, fmt:str='[%(asctime)s] %(levelname)s - %(message)s', datefmt:str='%Y-%m-%d %H:%M:%S') -> logging.Handler:
144
+ def create_log_handler(stderr:bool=False, fmt:str='[%(asctime)s] %(levelname)s - %(message)s', datefmt:str='%Y-%m-%d %H:%M:%S', level:int=logging.INFO) -> logging.Handler:
111
145
  """
112
146
  ログハンドラを生成します。
113
147
 
@@ -123,6 +157,7 @@ def create_log_handler(stderr:bool=False, fmt:str='[%(asctime)s] %(levelname)s -
123
157
  # tracebacks_word_wrap=False, log_time_format='[%Y-%m-%d %H:%M]')
124
158
  handler = loghandler.ColorfulStreamHandler(sys.stdout if not stderr else sys.stderr)
125
159
  handler.setFormatter(formatter)
160
+ handler.setLevel(level)
126
161
  return handler
127
162
 
128
163
  def create_console(stderr:bool=False, file=None) -> Console:
@@ -155,6 +190,7 @@ def default_logger(debug:bool=False, ver=version, webcall:bool=False) -> logging
155
190
  logging.Logger: ロガー
156
191
  """
157
192
  logger = logging.getLogger(ver.__appid__)
193
+ set_common_value('webcall', webcall)
158
194
  if not webcall:
159
195
  handler = create_log_handler()
160
196
  handler.setLevel(logging.DEBUG if debug else logging.INFO)
@@ -199,6 +235,7 @@ def load_config(mode:str, debug:bool=False, data=HOME_DIR, webcall:bool=False, v
199
235
  with open(log_conf_path) as f:
200
236
  log_config = yaml.safe_load(f)
201
237
  std_key = None
238
+ set_common_value('webcall', webcall)
202
239
  for k, h in log_config['handlers'].items():
203
240
  if 'filename' in h:
204
241
  h['filename'] = data / h['filename']
cmdbox/app/edge.py CHANGED
@@ -450,7 +450,7 @@ class Edge(object):
450
450
 
451
451
  status, res, headers = self.site_request(self.session.post, "/dosignin/gui", data=dict(name=user, password=password), ok_status=[200, 307])
452
452
  if status != 0 or headers.get('signin') is None:
453
- return 1, dict(warn=f"Signin failed.")
453
+ return 1, dict(warn=f"Signin failed.", headers=headers)
454
454
  status, self.user_info = self.load_user_info()
455
455
  self.user_info['auth_type'] = auth_type
456
456
  self.user_info['password'] = password
cmdbox/app/edge_tool.py CHANGED
@@ -56,7 +56,7 @@ class Tool(object):
56
56
  """
57
57
  self.session = session
58
58
  self.svcert_no_verify = svcert_no_verify
59
- self.endpoint = endpoint
59
+ self.endpoint = endpoint.rstrip('/')
60
60
  self.icon_path = icon_path
61
61
  self.user = user_info
62
62
  self.oauth2 = oauth2