cmdbox 0.5.3.1__py3-none-any.whl → 0.6.0__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 (188) hide show
  1. cmdbox/app/auth/__init__.py +0 -0
  2. cmdbox/app/auth/azure_signin.py +38 -0
  3. cmdbox/app/auth/azure_signin_saml.py +12 -0
  4. cmdbox/app/auth/github_signin.py +38 -0
  5. cmdbox/app/auth/google_signin.py +32 -0
  6. cmdbox/app/auth/signin.py +490 -287
  7. cmdbox/app/auth/signin_saml.py +61 -0
  8. cmdbox/app/common.py +48 -3
  9. cmdbox/app/edge.py +182 -213
  10. cmdbox/app/edge_tool.py +177 -0
  11. cmdbox/app/feature.py +10 -10
  12. cmdbox/app/features/cli/agent_base.py +477 -0
  13. cmdbox/app/features/cli/audit_base.py +1 -1
  14. cmdbox/app/features/cli/cmdbox_audit_search.py +24 -1
  15. cmdbox/app/features/cli/cmdbox_client_file_download.py +1 -1
  16. cmdbox/app/features/cli/cmdbox_cmd_list.py +105 -0
  17. cmdbox/app/features/cli/cmdbox_cmd_load.py +104 -0
  18. cmdbox/app/features/cli/cmdbox_edge_config.py +21 -7
  19. cmdbox/app/features/cli/cmdbox_edge_start.py +1 -1
  20. cmdbox/app/features/cli/cmdbox_gui_start.py +9 -132
  21. cmdbox/app/features/cli/cmdbox_gui_stop.py +4 -21
  22. cmdbox/app/features/cli/cmdbox_server_start.py +1 -1
  23. cmdbox/app/features/cli/cmdbox_web_apikey_add.py +1 -1
  24. cmdbox/app/features/cli/cmdbox_web_apikey_del.py +1 -1
  25. cmdbox/app/features/cli/cmdbox_web_genpass.py +0 -3
  26. cmdbox/app/features/cli/cmdbox_web_group_add.py +1 -1
  27. cmdbox/app/features/cli/cmdbox_web_group_del.py +1 -1
  28. cmdbox/app/features/cli/cmdbox_web_group_edit.py +1 -1
  29. cmdbox/app/features/cli/cmdbox_web_group_list.py +1 -1
  30. cmdbox/app/features/cli/cmdbox_web_start.py +119 -104
  31. cmdbox/app/features/cli/cmdbox_web_stop.py +1 -1
  32. cmdbox/app/features/cli/cmdbox_web_user_add.py +4 -4
  33. cmdbox/app/features/cli/cmdbox_web_user_del.py +1 -1
  34. cmdbox/app/features/cli/cmdbox_web_user_edit.py +4 -4
  35. cmdbox/app/features/cli/cmdbox_web_user_list.py +1 -1
  36. cmdbox/app/features/web/cmdbox_web_agent.py +250 -0
  37. cmdbox/app/features/web/cmdbox_web_do_signin.py +79 -103
  38. cmdbox/app/features/web/cmdbox_web_exec_cmd.py +8 -3
  39. cmdbox/app/features/web/cmdbox_web_signin.py +26 -4
  40. cmdbox/app/features/web/cmdbox_web_users.py +2 -0
  41. cmdbox/app/options.py +55 -2
  42. cmdbox/app/web.py +155 -27
  43. cmdbox/extensions/features.yml +18 -0
  44. cmdbox/extensions/sample_project/sample/app/features/cli/__init__.py +0 -0
  45. cmdbox/extensions/sample_project/sample/app/features/web/__init__.py +0 -0
  46. cmdbox/extensions/sample_project/sample/extensions/features.yml +23 -0
  47. cmdbox/extensions/sample_project/sample/extensions/user_list.yml +40 -6
  48. cmdbox/extensions/user_list.yml +37 -6
  49. cmdbox/licenses/{LICENSE.starlette.0.41.3(BSD License).txt → LICENSE.Authlib.1.5.2(BSD License).txt } +3 -1
  50. cmdbox/licenses/{LICENSE.pydantic_core.2.33.0(MIT License).txt → LICENSE.Deprecated.1.2.18(MIT License).txt } +2 -2
  51. cmdbox/licenses/{LICENSE.more-itertools.10.6.0(MIT License).txt → LICENSE.SQLAlchemy.2.0.40(MIT License).txt } +1 -1
  52. cmdbox/licenses/LICENSE.aiohttp.3.11.18(Apache Software License).txt +13 -0
  53. cmdbox/licenses/LICENSE.aiosignal.1.3.2(Apache Software License).txt +201 -0
  54. cmdbox/licenses/LICENSE.async-timeout.5.0.1(Apache Software License).txt +13 -0
  55. cmdbox/licenses/{LICENSE.watchfiles.1.0.0(MIT License).txt → LICENSE.attrs.25.3.0(UNKNOWN).txt} +1 -1
  56. cmdbox/licenses/{LICENSE.anyio.4.6.2.post1(MIT License).txt → LICENSE.cachetools.5.5.2(MIT License).txt } +1 -1
  57. cmdbox/licenses/LICENSE.distro.1.9.0(Apache Software License).txt +202 -0
  58. cmdbox/licenses/{LICENSE.pydantic_core.2.33.1(MIT License).txt → LICENSE.docstring_parser.0.16(MIT License).txt } +1 -1
  59. cmdbox/licenses/LICENSE.filelock.3.18.0(The Unlicense (Unlicense)).txt +24 -0
  60. cmdbox/licenses/LICENSE.frozenlist.1.6.0(Apache-2.0).txt +201 -0
  61. cmdbox/licenses/{LICENSE.starlette.0.46.1(BSD License).txt → LICENSE.fsspec.2025.3.2(BSD License).txt } +3 -1
  62. cmdbox/licenses/{LICENSE.argcomplete.3.6.1(Apache Software License).txt → LICENSE.google-adk.0.5.0(Apache Software License).txt } +25 -0
  63. cmdbox/licenses/LICENSE.google-api-python-client.2.169.0(Apache Software License).txt +201 -0
  64. cmdbox/licenses/LICENSE.google-auth-httplib2.0.2.0(Apache Software License).txt +201 -0
  65. cmdbox/licenses/LICENSE.google-auth.2.40.1(Apache Software License).txt +201 -0
  66. cmdbox/licenses/LICENSE.google-cloud-aiplatform.1.92.0(Apache 2.0).txt +202 -0
  67. cmdbox/licenses/LICENSE.google-cloud-bigquery.3.31.0(Apache Software License).txt +202 -0
  68. cmdbox/licenses/LICENSE.google-cloud-core.2.4.3(Apache Software License).txt +202 -0
  69. cmdbox/licenses/LICENSE.google-cloud-resource-manager.1.14.2(Apache Software License).txt +202 -0
  70. cmdbox/licenses/LICENSE.google-cloud-secret-manager.2.23.3(Apache Software License).txt +202 -0
  71. cmdbox/licenses/LICENSE.google-cloud-speech.2.32.0(Apache Software License).txt +202 -0
  72. cmdbox/licenses/LICENSE.google-cloud-storage.2.19.0(Apache Software License).txt +202 -0
  73. cmdbox/licenses/LICENSE.google-cloud-trace.1.16.1(Apache Software License).txt +202 -0
  74. cmdbox/licenses/LICENSE.google-crc32c.1.7.1(Apache 2.0).txt +202 -0
  75. cmdbox/licenses/LICENSE.google-genai.1.14.0(Apache Software License).txt +202 -0
  76. cmdbox/licenses/LICENSE.google-resumable-media.2.7.2(Apache Software License).txt +202 -0
  77. cmdbox/licenses/LICENSE.googleapis-common-protos.1.70.0(Apache Software License).txt +202 -0
  78. cmdbox/licenses/{LICENSE.fastapi.0.115.5(MIT License).txt → LICENSE.graphviz.0.20.3(MIT License).txt } +1 -1
  79. cmdbox/licenses/LICENSE.grpc-google-iam-v1.0.14.2(Apache Software License).txt +202 -0
  80. cmdbox/licenses/LICENSE.grpcio-status.1.71.0(Apache Software License).txt +610 -0
  81. cmdbox/licenses/LICENSE.grpcio.1.71.0(Apache Software License).txt +610 -0
  82. cmdbox/licenses/{LICENSE.uvicorn.0.34.0(BSD License).txt → LICENSE.httpcore.1.0.9(BSD License).txt } +1 -1
  83. cmdbox/licenses/LICENSE.httplib2.0.22.0(MIT License).txt +23 -0
  84. cmdbox/licenses/{LICENSE.tomli.2.1.0(MIT License).txt → LICENSE.httpx-sse.0.4.0(MIT).txt} +1 -1
  85. cmdbox/licenses/LICENSE.httpx.0.28.1(BSD License).txt +12 -0
  86. cmdbox/licenses/LICENSE.huggingface-hub.0.31.1(Apache Software License).txt +201 -0
  87. cmdbox/licenses/{LICENSE.charset-normalizer.3.4.0(MIT License).txt → LICENSE.jsonschema-specifications.2025.4.1(UNKNOWN).txt} +5 -7
  88. cmdbox/licenses/LICENSE.jsonschema.4.23.0(MIT License).txt +19 -0
  89. cmdbox/licenses/{LICENSE.pkginfo.1.10.0(MIT License).txt → LICENSE.litellm.1.69.0(MIT License).txt } +6 -1
  90. cmdbox/licenses/{LICENSE.redis.5.2.1(MIT License).txt → LICENSE.mcp.1.8.0(MIT License).txt } +1 -1
  91. cmdbox/licenses/LICENSE.multidict.6.4.3(Apache Software License).txt +13 -0
  92. cmdbox/licenses/{LICENSE.argcomplete.3.5.1(Apache Software License).txt → LICENSE.openai.1.75.0(Apache Software License).txt } +25 -1
  93. cmdbox/licenses/LICENSE.opentelemetry-api.1.33.0(Apache Software License).txt +201 -0
  94. cmdbox/licenses/LICENSE.opentelemetry-exporter-gcp-trace.1.9.0(Apache Software License).txt +201 -0
  95. cmdbox/licenses/LICENSE.opentelemetry-resourcedetector-gcp.1.9.0a0(Apache Software License).txt +201 -0
  96. cmdbox/licenses/LICENSE.opentelemetry-sdk.1.33.0(Apache Software License).txt +201 -0
  97. cmdbox/licenses/LICENSE.opentelemetry-semantic-conventions.0.54b0(Apache Software License).txt +201 -0
  98. cmdbox/licenses/LICENSE.propcache.0.3.1(Apache Software License).txt +202 -0
  99. cmdbox/licenses/LICENSE.proto-plus.1.26.1(Apache Software License).txt +202 -0
  100. cmdbox/licenses/{LICENSE.Pygments.2.18.0(BSD License).txt → LICENSE.protobuf.5.29.4(3-Clause BSD License).txt } +15 -8
  101. cmdbox/licenses/LICENSE.pyasn1.0.6.1(BSD License).txt +24 -0
  102. cmdbox/licenses/LICENSE.pyasn1_modules.0.4.2(BSD License).txt +24 -0
  103. cmdbox/licenses/LICENSE.pydantic-settings.2.9.1(MIT License).txt +21 -0
  104. cmdbox/licenses/{LICENSE.gevent.25.4.1(MIT).txt → LICENSE.pyparsing.3.2.3(MIT License).txt } +5 -12
  105. cmdbox/licenses/LICENSE.python-dateutil.2.9.0.post0(Apache Software License; BSD License).txt +54 -0
  106. cmdbox/licenses/LICENSE.referencing.0.36.2(UNKNOWN).txt +19 -0
  107. cmdbox/licenses/LICENSE.regex.2024.11.6(Apache Software License).txt +208 -0
  108. cmdbox/licenses/LICENSE.rpds-py.0.24.0(MIT).txt +19 -0
  109. cmdbox/licenses/{LICENSE.python-multipart.0.0.17(Apache Software License).txt → LICENSE.rsa.4.9.1(Apache Software License).txt } +1 -2
  110. cmdbox/licenses/{LICENSE.sphinx-intl.2.3.0(BSD License).txt → LICENSE.shapely.2.1.0(BSD License).txt } +6 -2
  111. cmdbox/licenses/LICENSE.sse-starlette.2.3.4(BSD License).txt +27 -0
  112. cmdbox/licenses/LICENSE.tiktoken.0.9.0(MIT License).txt +21 -0
  113. cmdbox/licenses/LICENSE.tokenizers.0.21.1(Apache Software License).txt +1 -0
  114. cmdbox/licenses/{LICENSE.six.1.16.0(MIT License).txt → LICENSE.tqdm.4.67.1(MIT License; Mozilla Public License 2.0 (MPL 2.0)).txt } +32 -1
  115. cmdbox/licenses/{LICENSE.rich.13.9.4(MIT License).txt → LICENSE.tzlocal.5.3.1(MIT License).txt } +3 -3
  116. cmdbox/licenses/LICENSE.uritemplate.4.1.1(Apache Software License; BSD License).txt +3 -0
  117. cmdbox/licenses/LICENSE.wrapt.1.17.2(BSD License).txt +24 -0
  118. cmdbox/licenses/LICENSE.yarl.1.20.0(Apache Software License).txt +202 -0
  119. cmdbox/licenses/files.txt +111 -17
  120. cmdbox/logconf_agent.yml +38 -0
  121. cmdbox/logconf_audit.yml +13 -5
  122. cmdbox/logconf_client.yml +13 -5
  123. cmdbox/logconf_cmdbox.yml +13 -5
  124. cmdbox/logconf_edge.yml +13 -5
  125. cmdbox/logconf_gui.yml +13 -5
  126. cmdbox/logconf_server.yml +13 -5
  127. cmdbox/logconf_web.yml +13 -5
  128. cmdbox/version.py +3 -2
  129. cmdbox/web/agent.html +263 -0
  130. cmdbox/web/assets/cmdbox/agent.js +335 -0
  131. cmdbox/web/assets/cmdbox/common.js +1111 -1020
  132. cmdbox/web/assets/cmdbox/signin.js +16 -3
  133. cmdbox/web/assets/cmdbox/users.js +1 -1
  134. cmdbox/web/assets/filer/filer.js +4 -2
  135. cmdbox/web/signin.html +10 -6
  136. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/METADATA +132 -35
  137. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/RECORD +161 -123
  138. cmdbox/app/features/web/cmdbox_web_load_pin.py +0 -43
  139. cmdbox/app/features/web/cmdbox_web_save_pin.py +0 -42
  140. cmdbox/licenses/LICENSE.Jinja2.3.1.4(BSD License).txt +0 -28
  141. cmdbox/licenses/LICENSE.Sphinx.8.1.3(BSD License).txt +0 -31
  142. cmdbox/licenses/LICENSE.babel.2.16.0(BSD License).txt +0 -27
  143. cmdbox/licenses/LICENSE.certifi.2025.1.31(Mozilla Public License 2.0 (MPL 2.0)).txt +0 -20
  144. cmdbox/licenses/LICENSE.click.8.1.8(BSD License).txt +0 -28
  145. cmdbox/licenses/LICENSE.cryptography.44.0.2(Apache Software License; BSD License).txt +0 -3
  146. cmdbox/licenses/LICENSE.greenlet.3.2.0(MIT AND Python-2.0).txt +0 -30
  147. cmdbox/licenses/LICENSE.keyring.25.5.0(MIT License).txt +0 -17
  148. cmdbox/licenses/LICENSE.numpy.2.2.4(BSD License).txt +0 -950
  149. cmdbox/licenses/LICENSE.pillow.11.0.0(CMU License (MIT-CMU)).txt +0 -1226
  150. cmdbox/licenses/LICENSE.pillow.11.1.0(CMU License (MIT-CMU)).txt +0 -1213
  151. cmdbox/licenses/LICENSE.prettytable.3.12.0(BSD License).txt +0 -30
  152. cmdbox/licenses/LICENSE.prompt_toolkit.3.0.50(BSD License).txt +0 -27
  153. cmdbox/licenses/LICENSE.psycopg.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt +0 -165
  154. cmdbox/licenses/LICENSE.pydantic.2.11.1(MIT License).txt +0 -21
  155. cmdbox/licenses/LICENSE.pydantic.2.11.3(MIT License).txt +0 -21
  156. cmdbox/licenses/LICENSE.python-dotenv.1.0.1(BSD License).txt +0 -27
  157. cmdbox/licenses/LICENSE.twine.5.1.1(Apache Software License).txt +0 -174
  158. cmdbox/licenses/LICENSE.typing_extensions.4.13.0(UNKNOWN).txt +0 -279
  159. cmdbox/licenses/LICENSE.urllib3.2.2.3(MIT License).txt +0 -21
  160. cmdbox/licenses/LICENSE.urllib3.2.3.0(MIT License).txt +0 -21
  161. cmdbox/licenses/LICENSE.uvicorn.0.34.1(BSD License).txt +0 -27
  162. cmdbox/licenses/LICENSE.watchfiles.1.0.4(MIT License).txt +0 -21
  163. cmdbox/licenses/LICENSE.websockets.14.1(BSD License).txt +0 -24
  164. cmdbox/licenses/LICENSE.zope.interface.7.1.1(Zope Public License).txt +0 -44
  165. /cmdbox/licenses/{LICENSE.typing_extensions.4.12.2(Python Software Foundation License).txt → LICENSE.aiohappyeyeballs.2.6.1(Python Software Foundation License).txt} +0 -0
  166. /cmdbox/licenses/{LICENSE.certifi.2024.8.30(Mozilla Public License 2.0 (MPL 2.0)).txt → LICENSE.certifi.2025.4.26(Mozilla Public License 2.0 (MPL 2.0)).txt} +0 -0
  167. /cmdbox/licenses/{LICENSE.charset-normalizer.3.4.1(MIT License).txt → LICENSE.charset-normalizer.3.4.2(MIT License).txt} +0 -0
  168. /cmdbox/licenses/{LICENSE.click.8.1.7(BSD License).txt → LICENSE.click.8.2.0(UNKNOWN).txt} +0 -0
  169. /cmdbox/licenses/{LICENSE.cryptography.43.0.3(Apache Software License; BSD License).txt → LICENSE.cryptography.44.0.3(Apache Software License; BSD License).txt} +0 -0
  170. /cmdbox/licenses/{LICENSE.gevent.24.11.1(MIT License).txt → LICENSE.gevent.25.4.2(MIT).txt} +0 -0
  171. /cmdbox/licenses/{LICENSE.importlib_metadata.8.5.0(Apache Software License).txt → LICENSE.google-api-core.2.24.2(Apache Software License).txt} +0 -0
  172. /cmdbox/licenses/{LICENSE.greenlet.3.1.1(MIT License).txt → LICENSE.greenlet.3.2.2(MIT AND Python-2.0).txt} +0 -0
  173. /cmdbox/licenses/{LICENSE.h11.0.14.0(MIT License).txt → LICENSE.h11.0.16.0(MIT License).txt} +0 -0
  174. /cmdbox/licenses/{LICENSE.nh3.0.2.18(MIT).txt → LICENSE.jiter.0.9.0(MIT License).txt} +0 -0
  175. /cmdbox/licenses/{LICENSE.more-itertools.10.5.0(MIT License).txt → LICENSE.more-itertools.10.7.0(MIT License).txt} +0 -0
  176. /cmdbox/licenses/{LICENSE.numpy.2.1.3(BSD License).txt → LICENSE.numpy.2.2.5(BSD License).txt} +0 -0
  177. /cmdbox/licenses/{LICENSE.packaging.24.2(Apache Software License; BSD License).txt → LICENSE.packaging.25.0(Apache Software License; BSD License).txt} +0 -0
  178. /cmdbox/licenses/{LICENSE.psycopg-binary.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE.psycopg-binary.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt} +0 -0
  179. /cmdbox/licenses/{LICENSE.psycopg-pool.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE.psycopg.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt} +0 -0
  180. /cmdbox/licenses/{LICENSE.pydantic.2.10.2(MIT License).txt → LICENSE.pydantic.2.11.4(MIT License).txt} +0 -0
  181. /cmdbox/licenses/{LICENSE.pydantic_core.2.27.1(MIT License).txt → LICENSE.pydantic_core.2.33.2(MIT License).txt} +0 -0
  182. /cmdbox/licenses/{LICENSE.redis.5.2.0(MIT License).txt → LICENSE.redis.6.0.0(MIT License).txt} +0 -0
  183. /cmdbox/licenses/{LICENSE.snowballstemmer.2.2.0(BSD License).txt → LICENSE.snowballstemmer.3.0.1(BSD License).txt} +0 -0
  184. /cmdbox/licenses/{LICENSE.uvicorn.0.32.1(BSD License).txt → LICENSE.uvicorn.0.34.2(BSD License).txt} +0 -0
  185. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/LICENSE +0 -0
  186. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/WHEEL +0 -0
  187. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/entry_points.txt +0 -0
  188. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/top_level.txt +0 -0
cmdbox/app/edge.py CHANGED
@@ -1,4 +1,4 @@
1
- from cmdbox.app import common, feature, options, web
1
+ from cmdbox.app import common, edge_tool, feature, options, web
2
2
  from cmdbox.app.commons import convert
3
3
  from cmdbox.app.options import Options
4
4
  from fastapi import FastAPI, Request, HTTPException
@@ -26,7 +26,7 @@ class Edge(object):
26
26
  self.appcls = appcls
27
27
  self.ver = ver
28
28
  self.options = options.Options.getInstance()
29
- self.tool = Tool(logger, appcls, ver)
29
+ self.tool = edge_tool.Tool(logger, appcls, ver)
30
30
  if self.ver is None:
31
31
  raise ValueError('ver is None')
32
32
  if self.appcls is None:
@@ -63,12 +63,30 @@ class Edge(object):
63
63
  conf = common.loadopt(conf_file)
64
64
  else:
65
65
  conf = dict()
66
+ skip_opts = []
67
+ input_opts = []
68
+ def _show_opts(choice_show:Dict[str, List[str]], value:str, ref_opts:List[Dict[str, Any]]) -> None:
69
+ for k, v in choice_show.items():
70
+ if k == value:
71
+ input_opts.extend(v)
72
+ else:
73
+ skip_opts.extend(v)
74
+ for r in ref_opts:
75
+ for opt in v:
76
+ if 'opt' not in r or r['opt'] is None:
77
+ continue
78
+ if 'choice_show' not in r or r['choice_show'] is None:
79
+ continue
80
+ _show_opts(r['choice_show'], '', [o for o in ref_opts if o['opt'] == opt])
66
81
  for r in ref_opts:
67
82
  if 'opt' not in r or r['opt'] is None:
68
83
  continue
69
84
  opt = r['opt']
70
- if opt in ['output_json', 'output_json_append', 'stdout_log', 'capture_stdout', 'capture_maxsize']:
85
+ if opt in ['tag', 'clmsg_id', 'output_json', 'output_json_append', 'stdout_log', 'capture_stdout', 'capture_maxsize']:
86
+ continue
87
+ if opt in skip_opts and opt not in input_opts:
71
88
  continue
89
+ choice_show = r['choice_show'] if 'choice_show' in r else dict()
72
90
  default = conf[opt] if opt in conf else None
73
91
  default = r['default'] if default is None and 'default' in r else default
74
92
  default = default if default is not None else ''
@@ -86,6 +104,7 @@ class Edge(object):
86
104
  value = questionary.select(f"{opt}:({help}):", choice, default=default).ask()
87
105
  else:
88
106
  value = questionary.text(f"{opt}:({help}):", default=default, validate=lambda v:not required or len(v)>0).ask()
107
+ _show_opts(choice_show, value, ref_opts)
89
108
  if r['type'] == Options.T_BOOL: value = value=='True'
90
109
  if r['type'] == Options.T_INT: value = int(value)
91
110
  if r['type'] == Options.T_FLOAT: value = float(value)
@@ -129,43 +148,71 @@ class Edge(object):
129
148
  if 'auth_type' not in opt or opt['auth_type'] is None:
130
149
  msg = dict(warn=f"Please run the `edge config` command. And please set the auth_type.")
131
150
  return msg
132
- if opt['auth_type'] == 'idpw' and ('user' not in opt or opt['user'] is None):
133
- msg = dict(warn=f"Please run the `edge config` command. And please set the user.")
134
- return msg
135
- if opt['auth_type'] == 'idpw' and ('password' not in opt or opt['password'] is None):
136
- msg = dict(warn=f"Please run the `edge config` command. And please set the password.")
137
- return msg
138
- if opt['auth_type'] == 'apikey' and ('apikey' not in opt or opt['apikey'] is None):
139
- msg = dict(warn=f"Please run the `edge config` command. And please set the apikey.")
140
- return msg
141
- if opt['auth_type'] == 'oauth2' and ('oauth2' not in opt or opt['oauth2'] is None):
142
- msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2.")
143
- return msg
144
- if opt['auth_type'] == 'oauth2' and ('oauth2_port' not in opt or opt['oauth2_port'] is None):
145
- msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2_port.")
146
- return msg
147
- if isinstance(opt['oauth2_port'], str):
148
- if not opt['oauth2_port'].isdigit():
149
- msg = dict(warn=f"Please set the numeric value in the oauth2_port. oauth2_port={opt['oauth2_port']}")
151
+ if opt['auth_type'] == 'idpw':
152
+ if 'user' not in opt or opt['user'] is None:
153
+ msg = dict(warn=f"Please run the `edge config` command. And please set the user.")
150
154
  return msg
151
- opt['oauth2_port'] = int(opt['oauth2_port'])
152
- if opt['oauth2'] == 'azure' and ('oauth2_tenant_id' not in opt or opt['oauth2_tenant_id'] is None):
153
- msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2_tenant_id.")
154
- return msg
155
- if opt['auth_type'] == 'oauth2' and ('oauth2_client_id' not in opt or opt['oauth2_client_id'] is None):
156
- msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2_client_id.")
157
- return msg
158
- if opt['auth_type'] == 'oauth2' and ('oauth2_client_secret' not in opt or opt['oauth2_client_secret'] is None):
159
- msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2_client_secret.")
160
- return msg
161
- if opt['auth_type'] == 'oauth2' and ('oauth2_timeout' not in opt or opt['oauth2_timeout'] is None):
162
- msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2_timeout.")
163
- return msg
164
- if isinstance(opt['oauth2_timeout'], str):
165
- if not opt['oauth2_timeout'].isdigit():
166
- msg = dict(warn=f"Please set the numeric value in the oauth2_timeout. oauth2_timeout={opt['oauth2_timeout']}")
155
+ if 'password' not in opt or opt['password'] is None:
156
+ msg = dict(warn=f"Please run the `edge config` command. And please set the password.")
167
157
  return msg
168
- opt['oauth2_timeout'] = int(opt['oauth2_timeout'])
158
+ if opt['auth_type'] == 'apikey':
159
+ if 'apikey' not in opt or opt['apikey'] is None:
160
+ msg = dict(warn=f"Please run the `edge config` command. And please set the apikey.")
161
+ return msg
162
+ if opt['auth_type'] == 'oauth2':
163
+ if 'oauth2' not in opt or opt['oauth2'] is None:
164
+ msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2.")
165
+ return msg
166
+ if 'oauth2_port' not in opt or opt['oauth2_port'] is None:
167
+ msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2_port.")
168
+ return msg
169
+ if isinstance(opt['oauth2_port'], str):
170
+ if not opt['oauth2_port'].isdigit():
171
+ msg = dict(warn=f"Please set the numeric value in the oauth2_port. oauth2_port={opt['oauth2_port']}")
172
+ return msg
173
+ opt['oauth2_port'] = int(opt['oauth2_port'])
174
+ if opt['oauth2'] == 'azure':
175
+ if 'oauth2_tenant_id' not in opt or opt['oauth2_tenant_id'] is None:
176
+ msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2_tenant_id.")
177
+ return msg
178
+ if 'oauth2_client_id' not in opt or opt['oauth2_client_id'] is None:
179
+ msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2_client_id.")
180
+ return msg
181
+ if 'oauth2_client_secret' not in opt or opt['oauth2_client_secret'] is None:
182
+ msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2_client_secret.")
183
+ return msg
184
+ if 'oauth2_timeout' not in opt or opt['oauth2_timeout'] is None:
185
+ msg = dict(warn=f"Please run the `edge config` command. And please set the oauth2_timeout.")
186
+ return msg
187
+ if isinstance(opt['oauth2_timeout'], str):
188
+ if not opt['oauth2_timeout'].isdigit():
189
+ msg = dict(warn=f"Please set the numeric value in the oauth2_timeout. oauth2_timeout={opt['oauth2_timeout']}")
190
+ return msg
191
+ opt['oauth2_timeout'] = int(opt['oauth2_timeout'])
192
+ if opt['auth_type'] == 'saml':
193
+ if 'saml' not in opt or opt['saml'] is None:
194
+ msg = dict(warn=f"Please run the `edge config` command. And please set the saml.")
195
+ return msg
196
+ if 'saml_port' not in opt or opt['saml_port'] is None:
197
+ msg = dict(warn=f"Please run the `edge config` command. And please set the saml.")
198
+ return msg
199
+ if isinstance(opt['saml_port'], str):
200
+ if not opt['saml_port'].isdigit():
201
+ msg = dict(warn=f"Please set the numeric value in the saml_port. saml_port={opt['saml_port']}")
202
+ return msg
203
+ opt['saml_port'] = int(opt['saml_port'])
204
+ if opt['saml'] == 'azure':
205
+ if 'saml_tenant_id' not in opt or opt['saml_tenant_id'] is None:
206
+ msg = dict(warn=f"Please run the `edge config` command. And please set the saml_tenant_id.")
207
+ return msg
208
+ if 'saml_timeout' not in opt or opt['saml_timeout'] is None:
209
+ msg = dict(warn=f"Please run the `edge config` command. And please set the saml_timeout.")
210
+ return msg
211
+ if isinstance(opt['saml_timeout'], str):
212
+ if not opt['saml_timeout'].isdigit():
213
+ msg = dict(warn=f"Please set the numeric value in the saml_timeout. saml_timeout={opt['saml_timeout']}")
214
+ return msg
215
+ opt['saml_timeout'] = int(opt['saml_timeout'])
169
216
  if 'svcert_no_verify' not in opt or opt['svcert_no_verify'] is not True:
170
217
  opt['svcert_no_verify'] = False
171
218
  if 'timeout' not in opt or opt['timeout'] is None:
@@ -184,9 +231,12 @@ class Edge(object):
184
231
  if self.svcert_no_verify:
185
232
  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
186
233
  status, msg = self.signin(opt.get('auth_type'), opt.get('user'), opt.get('password'), opt.get('apikey'),
187
- opt.get('oauth2'), int(opt.get('oauth2_port')),
234
+ opt.get('oauth2'), int(opt.get('oauth2_port', 8091)),
188
235
  opt.get('oauth2_tenant_id'), opt.get('oauth2_client_id'), opt.get('oauth2_client_secret'),
189
- int(opt.get('oauth2_timeout')))
236
+ int(opt.get('oauth2_timeout', 60)),
237
+ opt.get('saml'), int(opt.get('saml_port', 8091)),
238
+ opt.get('saml_tenant_id'), int(opt.get('saml_timeout', 60)))
239
+
190
240
  if status != 0:
191
241
  return msg
192
242
 
@@ -247,8 +297,8 @@ class Edge(object):
247
297
  def _job(thevent:threading.Event, pipe_cmd, prevq:queue.Queue):
248
298
  resq:queue.Queue = pipe_cmd['resq']
249
299
  del pipe_cmd['resq']
250
- tool = Tool(self.logger, self.appcls, self.ver)
251
- tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2)
300
+ tool = edge_tool.Tool(self.logger, self.appcls, self.ver)
301
+ tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
252
302
  feat:feature.Feature = self.options.get_cmd_attr(pipe_cmd['mode'], pipe_cmd['cmd'], 'feature')
253
303
  while not thevent.is_set():
254
304
  prevres = None if prevq is None else prevq.get(pipe_cmd['timeout'])
@@ -304,8 +354,8 @@ class Edge(object):
304
354
  for opt in opts:
305
355
  def mkcmd(opt):
306
356
  def _ex():
307
- tool = Tool(self.logger, self.appcls, self.ver)
308
- tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2)
357
+ tool = edge_tool.Tool(self.logger, self.appcls, self.ver)
358
+ tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
309
359
  feat:feature.Feature = self.options.get_cmd_attr(opt['mode'], opt['cmd'], 'feature')
310
360
  for status, ret in feat.edgerun(opt, tool, self.logger, self.timeout):
311
361
  pass
@@ -329,7 +379,7 @@ class Edge(object):
329
379
  items = []
330
380
  items.append(pystray.MenuItem('Gui', lambda: self.tool.open_browser('/gui')))
331
381
  for k, op in opens.items():
332
- def mkop(tool:Tool, href):
382
+ def mkop(tool:edge_tool.Tool, href):
333
383
  return lambda: tool.open_browser(href)
334
384
  items.append(pystray.MenuItem(op['html'], mkop(self.tool, op['href'])))
335
385
  return items
@@ -353,7 +403,9 @@ class Edge(object):
353
403
 
354
404
  def signin(self, auth_type:str, user:str, password:str, apikey:str,
355
405
  oauth2:str, oauth2_port:int, oauth2_tenant_id:str, oauth2_client_id:str, oauth2_client_secret:str,
356
- oauth2_timeout:int) -> Tuple[int, Dict[str, Any]]:
406
+ oauth2_timeout:int,
407
+ saml:str, saml_port:int, saml_tenant_id:str,
408
+ saml_timeout:int) -> Tuple[int, Dict[str, Any]]:
357
409
  """
358
410
  サインインを行います
359
411
 
@@ -368,6 +420,10 @@ class Edge(object):
368
420
  oauth2_client_id (str): OAuth2クライアントID
369
421
  oauth2_client_secret (str): OAuth2クライアントシークレット
370
422
  oauth2_timeout (int): OAuth2タイムアウト
423
+ saml (str): SAML
424
+ saml_port (int): SAMLポート
425
+ saml_tenant_id (str): SAMLテナントID
426
+ saml_timeout (int): SAMLタイムアウト
371
427
 
372
428
  Returns:
373
429
  Tuple[int, Dict[str, Any]]: 終了コード, メッセージ
@@ -375,13 +431,14 @@ class Edge(object):
375
431
  self.session = requests.Session()
376
432
  self.signed_in = False
377
433
  self.oauth2 = oauth2
434
+ self.saml = saml
378
435
  if auth_type == "noauth":
379
436
  status, res, _ = self.site_request(self.session.get, "/gui")
380
437
  if status != 0: return status, res
381
438
  status, self.user_info = self.load_user_info()
382
439
  self.user_info['auth_type'] = auth_type
383
440
  if status != 0: return status, res
384
- self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2)
441
+ self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
385
442
  return 0, dict(success="No auth.")
386
443
 
387
444
  # ID/PW認証を使用する場合
@@ -398,7 +455,7 @@ class Edge(object):
398
455
  self.user_info['auth_type'] = auth_type
399
456
  self.user_info['password'] = password
400
457
  if status != 0: return status, res
401
- self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2)
458
+ self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
402
459
  return 0, dict(success="Signin Success.")
403
460
 
404
461
  # APIKEY認証を使用する場合
@@ -413,7 +470,7 @@ class Edge(object):
413
470
  self.user_info['auth_type'] = auth_type
414
471
  self.user_info['apikey'] = apikey
415
472
  if status != 0: return status, res
416
- self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2)
473
+ self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
417
474
  return 0, dict(success="Signin Success.")
418
475
 
419
476
  # OAuth2認証を使用する場合
@@ -453,9 +510,9 @@ class Edge(object):
453
510
  status, self.user_info = self.load_user_info()
454
511
  self.user_info['auth_type'] = auth_type
455
512
  self.user_info['access_token'] = access_token
456
- if status != 0: return status, res
513
+ if status != 0: return res
457
514
  self.signed_in = True
458
- self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2)
515
+ self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
459
516
  return dict(success="Signin success. Please close your browser.")
460
517
  except Exception as e:
461
518
  raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
@@ -519,9 +576,9 @@ class Edge(object):
519
576
  status, self.user_info = self.load_user_info()
520
577
  self.user_info['auth_type'] = auth_type
521
578
  self.user_info['access_token'] = access_token
522
- if status != 0: return status, res
579
+ if status != 0: return res
523
580
  self.signed_in = True
524
- self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2)
581
+ self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
525
582
  return dict(success="Signin success. Please close your browser.")
526
583
  except Exception as e:
527
584
  raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
@@ -549,7 +606,6 @@ class Edge(object):
549
606
  time.sleep(1)
550
607
  return 0, dict(success="Signin success.")
551
608
 
552
-
553
609
  # Azure OAuth2を使用する場合
554
610
  elif oauth2 == "azure":
555
611
  if oauth2_tenant_id is None:
@@ -591,9 +647,9 @@ class Edge(object):
591
647
  status, self.user_info = self.load_user_info()
592
648
  self.user_info['auth_type'] = auth_type
593
649
  self.user_info['access_token'] = access_token
594
- if status != 0: return status, res
650
+ if status != 0: return res
595
651
  self.signed_in = True
596
- self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2)
652
+ self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
597
653
  return dict(success="Signin success. Please close your browser.")
598
654
  except Exception as e:
599
655
  raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
@@ -622,165 +678,78 @@ class Edge(object):
622
678
  time.sleep(1)
623
679
  return 0, dict(success="Signin success.")
624
680
 
625
- return 1, dict(warn="unsupported auth_type.")
626
-
627
- class Tool(object):
628
- def __init__(self, logger:logging.Logger, appcls=None, ver=None):
629
- self.logger = logger
630
- self.appcls = appcls
631
- self.ver = ver
632
-
633
- def notify(self, message:dict):
634
- """
635
- 通知メッセージを表示します
636
-
637
- Args:
638
- message (dict): メッセージ
639
- """
640
- if type(message) is list:
641
- message = message[0]
642
- if type(message) is not dict:
643
- message = {"info":str(message)}
644
- if self.logger.level == logging.DEBUG:
645
- self.logger.debug(f"notify: {common.to_str(message, slise=256)}")
646
- try:
647
- if 'success' in message and type(message['success']) == dict:
648
- message = "\n".join([f"{k}:{v}" for k, v in message['success'].items()])
649
- message = f'Success\n{message}'
650
- else:
651
- message = "\n".join([f"{k} : {v}" for k, v in message.items()])
652
- import plyer
653
- if hasattr(self, 'icon_path') and self.icon_path is not None:
654
- plyer.notification.notify(title=self.ver.__title__, message=str(message)[:256], app_icon=str(self.icon_path))
655
- else:
656
- plyer.notification.notify(title=self.ver.__title__, message=str(message)[:256])
657
- except Exception as e:
658
- self.logger.error(f"notify error. {e}", exc_info=True)
659
-
660
- def set_session(self, session:requests.Session, svcert_no_verify:bool, endpoint:str, icon_path:Path, user_info:Dict[str, Any], oauth2:str):
661
- """
662
- セッションを設定します
663
-
664
- Args:
665
- session (requests.Session): セッション
666
- svcert_no_verify (bool): サーバー証明書の検証を行わない
667
- endpoint (str): エンドポイント
668
- icon_path (Path): アイコン画像のパス
669
- user_info (Dict[str, Any]): ユーザー情報
670
- oauth2 (str): OAuth2
671
- """
672
- self.session = session
673
- self.svcert_no_verify = svcert_no_verify
674
- self.endpoint = endpoint
675
- self.icon_path = icon_path
676
- self.user = user_info
677
- self.oauth2 = oauth2
678
-
679
- def exec_cmd(self, opt:Dict[str, Any], logger:logging.Logger, timeout:int, prevres:Any=None) -> Tuple[int, Dict[str, Any]]:
680
- """
681
- この機能のエッジ側の実行を行います
682
-
683
- Args:
684
- opt (Dict[str, Any]): オプション
685
- logger (logging.Logger): ロガー
686
- timeout (int): タイムアウト時間
687
- prevres (Any): 前コマンドの結果。pipeline実行の実行結果を参照する時に使用します。
688
-
689
- Returns:
690
- Tuple[int, Dict[str, Any], Any]: 終了コード, 結果
691
- """
692
- if logger.level == logging.DEBUG:
693
- logger.debug(f"exec_cmd: {self.endpoint}/exec_cmd/{opt['title']}")
694
- if prevres is not None:
695
- headers = {'content-type':'application/octet-stream'}
696
- prevres = common.to_str(prevres)
697
- res = self.session.post(f"{self.endpoint}/exec_cmd/{opt['title']}", headers=headers, data=prevres,
698
- verify=not self.svcert_no_verify, timeout=timeout, allow_redirects=False)
699
- else:
700
- res = self.session.post(f"{self.endpoint}/exec_cmd/{opt['title']}",
701
- verify=not self.svcert_no_verify, timeout=timeout, allow_redirects=False)
702
-
703
- if res.status_code != 200:
704
- msg = dict(warn=f"Access failed. status_code={res.status_code}")
705
- logger.warning(f"Access failed. status_code={res.status_code}")
706
- return 1, msg
707
- else:
708
- ret = msg = res.json()
709
- if isinstance(msg, list):
710
- if len(msg) == 0:
711
- logger.warning(f"No result.")
712
- return 1, dict(warn="No result.")
713
- msg = msg[0]
714
- if isinstance(msg, dict) and 'success' not in msg:
715
- logger.warning(f"{msg}")
716
- return 1, ret
717
- if logger.level == logging.DEBUG:
718
- logger.debug(f"{common.to_str(ret, slise=255)}")
719
- return 0, ret
720
-
721
- def pub_result(self, title:str, output:str, timeout:int) -> Tuple[int, Dict[str, Any]]:
722
- """
723
- 結果を公開します
724
-
725
- Args:
726
- title (str): タイトル
727
- output (str): 出力
728
- logger (logging.Logger): ロガー
729
- timeout (int): タイムアウト時間
681
+ # saml認証を使用する場合
682
+ elif auth_type == "saml":
683
+ # Azure samlを使用する場合
684
+ if saml == "azure":
685
+ if saml_tenant_id is None:
686
+ return 1, dict(warn="Please specify the --saml_tenant_id option.")
687
+ saml_settings = dict(
688
+ strict=False,
689
+ debug=self.logger.level==logging.DEBUG,
690
+ idp=dict(
691
+ entityId=f'https://sts.windows.net/{saml_tenant_id}/',
692
+ singleSignOnService=dict(
693
+ url=f'https://login.microsoftonline.com/{saml_tenant_id}/saml2',
694
+ binding=f'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'),
695
+ certFingerprint='',
696
+ certFingerprintAlgorithm='sha1',
697
+ singleLogoutService=dict()),
698
+ sp=dict(
699
+ entityId=self.endpoint,
700
+ assertionConsumerService=dict(
701
+ url=f'http://localhost:{saml_port}/saml/azure/callback',
702
+ binding=f'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'),
703
+ attributeConsumingService=dict(),
704
+ singleLogoutService=dict(
705
+ binding=f'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'),
706
+ NameIDFormat=f'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
707
+ x509cert='',
708
+ privateKey=''))
709
+ request_data = dict(
710
+ https='off',
711
+ http_host='localhost',
712
+ server_port=saml_port,
713
+ script_name=f'/saml/azure/gui?next=gui',
714
+ post_data=dict(),
715
+ get_data=dict(n=common.random_string(8)),
716
+ )
717
+ from onelogin.saml2.auth import OneLogin_Saml2_Auth
718
+ auth = OneLogin_Saml2_Auth(request_data=request_data, old_settings=saml_settings)
719
+
720
+ # SAML認証のコールバックを受けるFastAPIサーバーを起動
721
+ fastapi = FastAPI()
722
+ @fastapi.post('/saml/azure/callback')
723
+ async def saml_azure_callback(req:Request):
724
+ form_data = await req.form()
725
+ try:
726
+ status, res, headers = self.site_request(self.session.post, f"/saml/azure/callback", data=form_data, ok_status=[200, 307])
727
+ if status != 0 or headers.get('signin') is None:
728
+ return dict(warn=f"Signin failed.")
729
+ status, self.user_info = self.load_user_info()
730
+ self.user_info['auth_type'] = auth_type
731
+ if status != 0: return res
732
+ self.signed_in = True
733
+ self.user_info['saml_token'] = convert.str2b64str(common.to_str(form_data._dict))
734
+ self.tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
735
+ return dict(success="Signin success. Please close your browser.")
736
+ except Exception as e:
737
+ raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
730
738
 
731
- Returns:
732
- Tuple[int, Dict[str, Any]]: 終了コード, メッセージ
733
- """
734
- output = common.to_str(output)
735
- data = f'title={urllib.parse.quote(title)}&output={urllib.parse.quote(output)}'
736
- headers = {'content-type':'application/x-www-form-urlencoded'}
737
- res = self.session.post(f"{self.endpoint}/result/pub", headers=headers, data=data,
738
- verify=not self.svcert_no_verify, timeout=timeout, allow_redirects=False)
739
- if res.status_code != 200:
740
- msg = dict(warn=f"Access failed. status_code={res.status_code}")
741
- return 1, msg
742
- else:
743
- msg = res.json()
744
- return 0, msg
739
+ if not hasattr(self, 'thUvicorn') or not self.thUvicorn.is_alive():
740
+ self.thUvicorn = web.ThreadedUvicorn(self.logger, Config(app=fastapi, host='localhost', port=saml_port), {})
741
+ self.thUvicorn.start()
742
+ time.sleep(1)
745
743
 
746
- def open_browser(self, path:str) -> Tuple[int, Dict[str, str]]:
747
- """
748
- 指定したパスをブラウザで開きます。
749
- この時認証情報を含めて開きます。
744
+ # SAML認証のリクエストを送信
745
+ webbrowser.open(auth.login())
750
746
 
751
- Args:
752
- path (str): パス
747
+ # 認証完了まで指定秒数待つ
748
+ tm = time.time()
749
+ while not self.signed_in:
750
+ if time.time() - tm > saml_timeout:
751
+ return 1, dict(warn="Signin Timeout.")
752
+ time.sleep(1)
753
+ return 0, dict(success="Signin success.")
753
754
 
754
- Returns:
755
- Tuple[int, Dict[str, str]]: 終了コード, メッセージ
756
- """
757
- path = f"/{path}" if not path.startswith('/') else path
758
- if not hasattr(self, 'user'):
759
- webbrowser.open(f"{self.endpoint}{path}")
760
- return 0, dict(success="Open browser.")
761
- token = dict(auth_type=self.user['auth_type'])
762
- if self.user['auth_type'] == "noauth":
763
- webbrowser.open(f"{self.endpoint}{path}")
764
- return 0, dict(success="Open browser.")
765
- elif self.user['auth_type'] == "idpw":
766
- hashed = self.user['password'] if self.user['hash']=='plain' else common.hash_password(self.user['password'], self.user['hash'])
767
- token = dict(**token, **dict(user=self.user['name'], token=common.encrypt(path, hashed)))
768
- token = convert.str2b64str(common.to_str(token))
769
- webbrowser.open(f"{self.endpoint}/dosignin_token/{token}{path}")
770
- return 0, dict(success="Open browser.")
771
- elif self.user['auth_type'] == "apikey":
772
- hashed = common.hash_password(self.user['apikey'], 'sha1')
773
- token = dict(**token, **dict(user=self.user['name'], token=common.encrypt(path, hashed)))
774
- token = convert.str2b64str(common.to_str(token))
775
- webbrowser.open(f"{self.endpoint}/dosignin_token/{token}{path}")
776
- return 0, dict(success="Open browser.")
777
- elif self.user['auth_type'] == "oauth2" and self.oauth2 == 'google':
778
- webbrowser.open(f"{self.endpoint}/oauth2/google/session/{self.user['access_token']}{path}")
779
- return 0, dict(success="Open browser.")
780
- elif self.user['auth_type'] == "oauth2" and self.oauth2 == 'github':
781
- webbrowser.open(f"{self.endpoint}/oauth2/github/session/{self.user['access_token']}{path}")
782
- return 0, dict(success="Open browser.")
783
- elif self.user['auth_type'] == "oauth2" and self.oauth2 == 'azure':
784
- webbrowser.open(f"{self.endpoint}/oauth2/azure/session/{self.user['access_token']}{path}")
785
- return 0, dict(success="Open browser.")
786
755
  return 1, dict(warn="unsupported auth_type.")