tccli 3.0.1190.1__py2.py3-none-any.whl → 3.0.1192.1__py2.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.
Files changed (61) hide show
  1. tccli/__init__.py +1 -1
  2. tccli/command.py +7 -1
  3. tccli/configure.py +11 -3
  4. tccli/loaders.py +43 -8
  5. tccli/oauth.py +115 -0
  6. tccli/plugin.py +30 -0
  7. tccli/plugins/__init__.py +0 -0
  8. tccli/plugins/auth/__init__.py +59 -0
  9. tccli/plugins/auth/browser_flow.py +88 -0
  10. tccli/plugins/auth/login.py +130 -0
  11. tccli/plugins/auth/logout.py +21 -0
  12. tccli/plugins/auth/texts.py +30 -0
  13. tccli/plugins/test/__init__.py +87 -0
  14. tccli/plugins/test/add.py +31 -0
  15. tccli/services/apm/v20210622/api.json +19 -0
  16. tccli/services/cam/cam_client.py +138 -32
  17. tccli/services/cam/v20190116/api.json +203 -0
  18. tccli/services/cam/v20190116/examples.json +16 -0
  19. tccli/services/cdb/v20170320/api.json +13 -4
  20. tccli/services/cfw/cfw_client.py +53 -0
  21. tccli/services/cfw/v20190904/api.json +473 -0
  22. tccli/services/cfw/v20190904/examples.json +8 -0
  23. tccli/services/ckafka/ckafka_client.py +53 -0
  24. tccli/services/ckafka/v20190819/api.json +80 -0
  25. tccli/services/ckafka/v20190819/examples.json +8 -0
  26. tccli/services/cls/v20201016/examples.json +1 -1
  27. tccli/services/dasb/dasb_client.py +53 -0
  28. tccli/services/dasb/v20191018/api.json +168 -0
  29. tccli/services/dasb/v20191018/examples.json +8 -0
  30. tccli/services/dlc/v20210125/api.json +298 -45
  31. tccli/services/dlc/v20210125/examples.json +21 -21
  32. tccli/services/dsgc/v20190723/api.json +13 -3
  33. tccli/services/emr/v20190103/api.json +8 -8
  34. tccli/services/ess/v20201111/api.json +49 -16
  35. tccli/services/ess/v20201111/examples.json +7 -1
  36. tccli/services/essbasic/v20210526/api.json +28 -1
  37. tccli/services/essbasic/v20210526/examples.json +43 -1
  38. tccli/services/irp/v20220805/api.json +11 -2
  39. tccli/services/lke/v20231130/api.json +82 -4
  40. tccli/services/mps/v20190612/api.json +126 -5
  41. tccli/services/ocr/v20181119/api.json +10 -0
  42. tccli/services/ocr/v20181119/examples.json +1 -1
  43. tccli/services/omics/v20221128/api.json +13 -2
  44. tccli/services/region/v20220627/api.json +11 -11
  45. tccli/services/region/v20220627/examples.json +1 -1
  46. tccli/services/tat/v20201028/api.json +10 -0
  47. tccli/services/tcb/v20180608/api.json +2 -2
  48. tccli/services/tdmq/v20200217/api.json +2 -2
  49. tccli/services/tdmq/v20200217/examples.json +2 -2
  50. tccli/services/tmt/v20180321/api.json +2 -2
  51. tccli/services/vdb/v20230616/api.json +38 -1
  52. tccli/services/vdb/v20230616/examples.json +2 -2
  53. tccli/services/vod/v20180717/api.json +30 -9
  54. tccli/services/vod/v20180717/examples.json +1 -1
  55. tccli/services/vpc/v20170312/api.json +3 -3
  56. tccli/services/wedata/v20210820/api.json +1 -1
  57. {tccli-3.0.1190.1.dist-info → tccli-3.0.1192.1.dist-info}/METADATA +2 -2
  58. {tccli-3.0.1190.1.dist-info → tccli-3.0.1192.1.dist-info}/RECORD +61 -51
  59. {tccli-3.0.1190.1.dist-info → tccli-3.0.1192.1.dist-info}/WHEEL +0 -0
  60. {tccli-3.0.1190.1.dist-info → tccli-3.0.1192.1.dist-info}/entry_points.txt +0 -0
  61. {tccli-3.0.1190.1.dist-info → tccli-3.0.1192.1.dist-info}/license_files/LICENSE +0 -0
tccli/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = '3.0.1190.1'
1
+ __version__ = '3.0.1192.1'
tccli/command.py CHANGED
@@ -6,6 +6,8 @@ import copy
6
6
  import tccli.services as Services
7
7
  import tccli.options_define as Options_define
8
8
  from collections import OrderedDict
9
+
10
+ from tccli import oauth
9
11
  from tccli.utils import Utils
10
12
  from tccli.argument import CLIArgument, CustomArgument, ListArgument, BooleanArgument
11
13
  from tccli.exceptions import UnknownArgumentError
@@ -176,12 +178,15 @@ class ServiceCommand(BaseCommand):
176
178
  service_model = self._get_service_model()
177
179
  for action in service_model["actions"]:
178
180
  action_model = service_model["actions"][action]
181
+ action_caller = action_model.get("action_caller", None)
182
+ if not action_caller:
183
+ action_caller = Services.action_caller(self._service_name)()[action]
179
184
  command_map[action] = ActionCommand(
180
185
  service_name=self._service_name,
181
186
  version=self._version,
182
187
  action_name=action,
183
188
  action_model=action_model,
184
- action_caller=Services.action_caller(self._service_name)()[action],
189
+ action_caller=action_caller,
185
190
  )
186
191
  return command_map
187
192
 
@@ -286,6 +291,7 @@ class ActionCommand(BaseCommand):
286
291
  action_parameters = self.cli_unfold_argument.build_action_parameters(parsed_args)
287
292
  else:
288
293
  action_parameters = self._build_action_parameters(parsed_args, self.argument_map)
294
+ oauth.maybe_refresh_credential(parsed_globals.profile if parsed_globals.profile else "default")
289
295
  return self._action_caller(action_parameters, vars(parsed_globals))
290
296
 
291
297
  def create_help_command(self):
tccli/configure.py CHANGED
@@ -416,16 +416,24 @@ class ConfigureCommand(BasicConfigure):
416
416
 
417
417
  def init_configures(self):
418
418
  config = {}
419
- if not self._profile_existed("default.configure")[0]:
419
+ import argparse
420
+ parser = argparse.ArgumentParser()
421
+ parser.add_argument("--profile", type=str)
422
+ args, _ = parser.parse_known_args()
423
+ profile = args.profile or "default"
424
+ profile_file = "%s.configure" % profile
425
+
426
+ if not self._profile_existed(profile_file)[0]:
420
427
  config = {
421
428
  "region": "ap-guangzhou",
422
429
  "output": "json",
423
430
  "arrayCount": 10,
424
431
  "warning": "off"
425
432
  }
426
- self._init_configure("default.configure", config)
433
+ self._init_configure(profile_file, config)
434
+
427
435
  for profile_name in os.listdir(self.cli_path):
428
- if profile_name == "default.configure":
436
+ if profile_name == profile_file:
429
437
  continue
430
438
  if profile_name.endswith(".configure"):
431
439
  self._init_configure(profile_name, {})
tccli/loaders.py CHANGED
@@ -9,6 +9,7 @@ from tccli.utils import Utils
9
9
  from tccli import __version__
10
10
  from tccli.services import SERVICE_VERSIONS
11
11
  from collections import OrderedDict
12
+ import tccli.plugin as plugin
12
13
 
13
14
  BASE_TYPE = ["int64", "uint64", "string", "float", "bool", "date", "datetime", "datetime_iso", "binary"]
14
15
  CLI_BASE_TYPE = ["Integer", "String", "Float", "Timestamp", "Boolean", "Binary"]
@@ -175,7 +176,15 @@ class Loader(object):
175
176
  return version[1:5] + "-" + version[5:7] + "-" + version[7:9]
176
177
 
177
178
  def get_available_services(self):
178
- return SERVICE_VERSIONS
179
+ services = copy.deepcopy(SERVICE_VERSIONS)
180
+ for name, vers in plugin.import_plugins().items():
181
+ if name not in services:
182
+ services[name] = []
183
+ for ver, spec in vers.items():
184
+ api_ver = spec["metadata"]["apiVersion"]
185
+ if api_ver not in services[name]:
186
+ services[name].append(api_ver)
187
+ return services
179
188
 
180
189
  def get_service_default_version(self, service):
181
190
  args = sys.argv[1:]
@@ -194,15 +203,41 @@ class Loader(object):
194
203
  services_path = self.get_services_path()
195
204
  version = "v" + version.replace('-', '')
196
205
  apis_path = os.path.join(services_path, service, version, "api.json")
197
- if not os.path.exists(apis_path):
206
+ model = {
207
+ "metadata": {},
208
+ "actions": {},
209
+ "objects": {},
210
+ }
211
+ if os.path.exists(apis_path):
212
+ if six.PY2:
213
+ with open(apis_path, 'r') as f:
214
+ model = json.load(f)
215
+ else:
216
+ with open(apis_path, 'r', encoding='utf-8') as f:
217
+ model = json.load(f)
218
+
219
+ # merge plugins
220
+ for plugin_name, vers in plugin.import_plugins().items():
221
+
222
+ if plugin_name != service:
223
+ continue
224
+
225
+ for ver, spec in vers.items():
226
+
227
+ # 2017-03-12 -> v20170312
228
+ compact_ver = 'v' + ver.replace('-', '')
229
+
230
+ if compact_ver != version:
231
+ continue
232
+
233
+ model["metadata"].update(spec["metadata"])
234
+ model["actions"].update(spec["actions"])
235
+ model["objects"].update(spec["objects"])
236
+
237
+ if not model:
198
238
  raise Exception("Not find service:%s version:%s model" % (service, version))
199
239
 
200
- if six.PY2:
201
- with open(apis_path, 'r') as f:
202
- return json.load(f)
203
- else:
204
- with open(apis_path, 'r', encoding='utf-8') as f:
205
- return json.load(f)
240
+ return model
206
241
 
207
242
  def get_service_description(self, service, version):
208
243
  service_model = self.get_service_model(service, version)
tccli/oauth.py ADDED
@@ -0,0 +1,115 @@
1
+ import json
2
+ import os
3
+ import time
4
+
5
+ import requests
6
+ import uuid
7
+
8
+ _API_ENDPOINT = "https://cli.cloud.tencent.com"
9
+ _CRED_REFRESH_SAFE_DUR = 60 * 5
10
+ _ACCESS_REFRESH_SAFE_DUR = 60 * 5
11
+
12
+
13
+ def maybe_refresh_credential(profile):
14
+ cred_path = cred_path_of_profile(profile)
15
+ try:
16
+ with open(cred_path, "r") as cred_file:
17
+ cred = json.load(cred_file)
18
+ except IOError:
19
+ # file not found, don't check
20
+ return
21
+
22
+ if cred.get("type") != "oauth":
23
+ return
24
+
25
+ try:
26
+ now = time.time()
27
+
28
+ expires_at = cred["expiresAt"]
29
+ if expires_at - now > _CRED_REFRESH_SAFE_DUR:
30
+ return
31
+
32
+ token_info = cred["oauth"]
33
+ site = token_info["site"]
34
+ access_expires = token_info["expiresAt"]
35
+ if access_expires - now < _ACCESS_REFRESH_SAFE_DUR:
36
+ refresh_token = token_info["refreshToken"]
37
+ open_id = token_info["openId"]
38
+ new_token = refresh_user_token(refresh_token, open_id, site)
39
+ token_info.update(new_token)
40
+
41
+ access_token = token_info["accessToken"]
42
+ new_cred = get_temp_cred(access_token, site)
43
+ save_credential(token_info, new_cred, profile)
44
+
45
+ except KeyError as e:
46
+ print("failed to refresh credential, your credential file(%s) is corrupted, %s" % (cred_path, e))
47
+
48
+ except Exception as e:
49
+ print("failed to refresh credential, %s" % e)
50
+
51
+
52
+ def refresh_user_token(ref_token, open_id, site):
53
+ api_endpoint = _API_ENDPOINT + "/refresh_user_token"
54
+ body = {
55
+ "TraceId": str(uuid.uuid4()),
56
+ "RefreshToken": ref_token,
57
+ "OpenId": open_id,
58
+ "Site": site,
59
+ }
60
+ http_response = requests.post(api_endpoint, json=body, verify=False)
61
+ resp = http_response.json()
62
+
63
+ if "Error" in resp:
64
+ raise ValueError("refresh_user_token: %s" % json.dumps(resp))
65
+
66
+ return {
67
+ "accessToken": resp["AccessToken"],
68
+ "expiresAt": resp["ExpiresAt"],
69
+ }
70
+
71
+
72
+ def get_temp_cred(access_token, site):
73
+ api_endpoint = _API_ENDPOINT + "/get_temp_cred"
74
+ body = {
75
+ "TraceId": str(uuid.uuid4()),
76
+ "AccessToken": access_token,
77
+ "Site": site,
78
+ }
79
+ http_response = requests.post(api_endpoint, json=body, verify=False)
80
+ resp = http_response.json()
81
+
82
+ if "Error" in resp:
83
+ raise ValueError("get_temp_key: %s" % json.dumps(resp))
84
+
85
+ return {
86
+ "secretId": resp["SecretId"],
87
+ "secretKey": resp["SecretKey"],
88
+ "token": resp["Token"],
89
+ "expiresAt": resp["ExpiresAt"],
90
+ }
91
+
92
+
93
+ def cred_path_of_profile(profile):
94
+ return os.path.join(os.path.expanduser("~"), ".tccli", profile + ".credential")
95
+
96
+
97
+ def save_credential(token, new_cred, profile):
98
+ cred_path = cred_path_of_profile(profile)
99
+
100
+ cred = {
101
+ "type": "oauth",
102
+ "secretId": new_cred["secretId"],
103
+ "secretKey": new_cred["secretKey"],
104
+ "token": new_cred["token"],
105
+ "expiresAt": new_cred["expiresAt"],
106
+ "oauth": {
107
+ "openId": token["openId"],
108
+ "accessToken": token["accessToken"],
109
+ "expiresAt": token["expiresAt"],
110
+ "refreshToken": token["refreshToken"],
111
+ "site": token["site"],
112
+ },
113
+ }
114
+ with open(cred_path, "w") as cred_file:
115
+ json.dump(cred, cred_file, indent=4)
tccli/plugin.py ADDED
@@ -0,0 +1,30 @@
1
+ import importlib
2
+ import logging
3
+ import pkgutil
4
+
5
+ import tccli.plugins as plugins
6
+
7
+ _plugins = {}
8
+ _imported = False
9
+
10
+
11
+ def import_plugins():
12
+ global _imported
13
+
14
+ if not _imported:
15
+ _reimport_plugins()
16
+ _imported = True
17
+
18
+ return _plugins
19
+
20
+
21
+ def _reimport_plugins():
22
+ for _, name, _ in pkgutil.iter_modules(plugins.__path__, plugins.__name__ + "."):
23
+ mod = importlib.import_module(name)
24
+ register_service = getattr(mod, "register_service", None)
25
+ if not register_service:
26
+ logging.warning("invalid module %s" % name)
27
+ continue
28
+ register_service(_plugins)
29
+
30
+ return _plugins
File without changes
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+ from tccli.plugins.auth.login import login_command_entrypoint
3
+ from tccli.plugins.auth.logout import logout_command_entrypoint
4
+
5
+ service_name = "auth"
6
+ service_version = "2024-08-20"
7
+
8
+ _spec = {
9
+ "metadata": {
10
+ "serviceShortName": service_name,
11
+ "apiVersion": service_version,
12
+ "description": "auth related commands",
13
+ },
14
+ "actions": {
15
+ "login": {
16
+ "name": "登陆",
17
+ "document": "login through sso",
18
+ "input": "loginRequest",
19
+ "output": "loginResponse",
20
+ "action_caller": login_command_entrypoint,
21
+ },
22
+ "logout": {
23
+ "name": "登出",
24
+ "document": "remove local credential file",
25
+ "input": "logoutRequest",
26
+ "output": "logoutResponse",
27
+ "action_caller": logout_command_entrypoint,
28
+ },
29
+ },
30
+ "objects": {
31
+ "loginRequest": {
32
+ "members": [
33
+ {
34
+ "name": "browser",
35
+ "member": "string",
36
+ "type": "string",
37
+ "required": False,
38
+ "document": "use browser=no to indicate no browser login mode",
39
+ },
40
+ ],
41
+ },
42
+ "loginResponse": {
43
+ "members": [],
44
+ },
45
+ "logoutRequest": {
46
+ "members": [],
47
+ },
48
+ "logoutResponse": {
49
+ "members": [],
50
+ },
51
+ },
52
+ "version": "1.0",
53
+ }
54
+
55
+
56
+ def register_service(specs):
57
+ specs[service_name] = {
58
+ service_version: _spec,
59
+ }
@@ -0,0 +1,88 @@
1
+ import time
2
+ import traceback
3
+ import socket
4
+ from threading import Thread
5
+ from tccli import oauth
6
+
7
+ try:
8
+ from urlparse import urlparse, parse_qs
9
+ from Queue import Queue
10
+ from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
11
+ from SocketServer import ThreadingTCPServer, TCPServer
12
+ except ImportError:
13
+ from urllib.parse import urlparse, parse_qs
14
+ from queue import Queue
15
+ from http.server import HTTPServer, BaseHTTPRequestHandler
16
+ from socketserver import ThreadingTCPServer, TCPServer
17
+
18
+
19
+ # chrome keeps previous connection alive, so use threading to avoid blocking
20
+ class ThreadingHTTPServer(ThreadingTCPServer):
21
+ allow_reuse_address = 1
22
+
23
+ def server_bind(self):
24
+ """Override server_bind to store the server name."""
25
+ TCPServer.server_bind(self)
26
+ host, port = self.socket.getsockname()[:2]
27
+ self.server_name = socket.getfqdn(host)
28
+ self.server_port = port
29
+
30
+
31
+ class HTTPHandler(BaseHTTPRequestHandler):
32
+ result_queue = Queue(1)
33
+
34
+ def do_GET(self):
35
+ try:
36
+ parsed_url = urlparse(self.path)
37
+ query_vals = parse_qs(parsed_url.query)
38
+
39
+ open_id = query_vals.get("open_id")[0]
40
+ access_token = query_vals.get("access_token")[0]
41
+ refresh_token = query_vals.get("refresh_token")[0]
42
+ expires_at = int(query_vals.get("expires_at")[0])
43
+ state = query_vals.get("state")[0]
44
+ redirect_url = query_vals.get("redirect_url")[0]
45
+ site = query_vals.get("site")[0]
46
+ token = {
47
+ "openId": open_id,
48
+ "accessToken": access_token,
49
+ "refreshToken": refresh_token,
50
+ "expiresAt": expires_at,
51
+ "state": state,
52
+ "site": site,
53
+ }
54
+ cred = oauth.get_temp_cred(token["accessToken"], token["site"])
55
+ self.result_queue.put((token, cred))
56
+ self.send_response(307)
57
+ self.send_header("Location", redirect_url)
58
+ self.end_headers()
59
+ except Exception:
60
+ err = traceback.format_exc()
61
+ print(err)
62
+ self.send_response(400)
63
+ self.end_headers()
64
+ self.wfile.write("login failed due to the following error:\n\n".encode("utf-8"))
65
+ self.wfile.write(err.encode("utf-8"))
66
+ self.wfile.flush()
67
+
68
+ # suppress debug message
69
+ def log_message(self, format, *args):
70
+ pass
71
+
72
+
73
+ def try_run(start_search_port, end_search_port):
74
+ port = start_search_port
75
+
76
+ while port <= end_search_port:
77
+ server_address = ('', port)
78
+ try:
79
+ ThreadingHTTPServer.daemon_threads = True
80
+ httpd = ThreadingHTTPServer(server_address, HTTPHandler)
81
+ t = Thread(target=httpd.serve_forever)
82
+ t.setDaemon(True)
83
+ t.start()
84
+ return port, HTTPHandler.result_queue
85
+ except socket.error:
86
+ port += 1
87
+
88
+ raise socket.error("no port available from range [%d, %d]" % (start_search_port, end_search_port))
@@ -0,0 +1,130 @@
1
+ # coding: utf-8
2
+ import base64
3
+ import json
4
+ import random
5
+ import string
6
+ import sys
7
+ import time
8
+ from six.moves.urllib.parse import urlencode
9
+ import webbrowser
10
+
11
+ from tccli import oauth
12
+ from tccli.plugins.auth import texts
13
+
14
+ _APP_ID = 100038427476
15
+ _AUTH_URL = "https://cloud.tencent.com/open/authorize"
16
+ _REDIRECT_URL = "https://cli.cloud.tencent.com/oauth"
17
+ _SITE = "cn"
18
+ _DEFAULT_LANG = "zh-CN"
19
+
20
+ _START_SEARCH_PORT = 9000
21
+ _END_SEARCH_PORT = _START_SEARCH_PORT + 100
22
+
23
+
24
+ def print_message(msg):
25
+ print(msg)
26
+ sys.stdout.flush()
27
+
28
+
29
+ def login_command_entrypoint(args, parsed_globals):
30
+ language = parsed_globals.get("language")
31
+ if not language:
32
+ language = _DEFAULT_LANG
33
+ texts.set_lang(language)
34
+
35
+ profile = parsed_globals.get("profile", "default")
36
+ if not profile:
37
+ profile = "default"
38
+
39
+ browser = args.get("browser")
40
+
41
+ login(browser != "no", profile, language)
42
+
43
+
44
+ def login(use_browser, profile, language):
45
+ characters = string.ascii_letters + string.digits
46
+ state = ''.join(random.choice(characters) for _ in range(10))
47
+
48
+ if use_browser:
49
+ token, cred = _get_token(state, language)
50
+ else:
51
+ token, cred = _get_token_no_browser(state, language)
52
+
53
+ if token["state"] != state:
54
+ raise ValueError("invalid state %s" % token["state"])
55
+
56
+ oauth.save_credential(token, cred, profile)
57
+
58
+ print_message("")
59
+ print_message(texts.get("login_success") % oauth.cred_path_of_profile(profile))
60
+
61
+
62
+ def _get_token(state, language):
63
+ from tccli.plugins.auth import browser_flow
64
+
65
+ port, result_queue = browser_flow.try_run(_START_SEARCH_PORT, _END_SEARCH_PORT)
66
+
67
+ redirect_params = {
68
+ "redirect_url": "http://localhost:%d" % port,
69
+ "lang": language,
70
+ "site": _SITE,
71
+ }
72
+ redirect_query = urlencode(redirect_params)
73
+ redirect_url = _REDIRECT_URL + "?" + redirect_query
74
+ url_params = {
75
+ "scope": "login",
76
+ "app_id": _APP_ID,
77
+ "redirect_url": redirect_url,
78
+ "state": state,
79
+ }
80
+ url_query = urlencode(url_params)
81
+ auth_url = _AUTH_URL + "?" + url_query
82
+
83
+ if not webbrowser.open(auth_url):
84
+ print_message(texts.get("login_failed_due_to_no_browser"))
85
+ sys.exit(1)
86
+
87
+ print_message(texts.get("login_prompt"))
88
+ print_message(auth_url)
89
+
90
+ # use polling to avoid being unresponsive in python2
91
+ while result_queue.empty():
92
+ time.sleep(1)
93
+
94
+ result = result_queue.get()
95
+ if isinstance(result, Exception):
96
+ raise result
97
+
98
+ return result
99
+
100
+
101
+ def _get_token_no_browser(state, language):
102
+ redirect_params = {
103
+ "browser": "no",
104
+ "lang": language,
105
+ "site": _SITE,
106
+ }
107
+ redirect_query = urlencode(redirect_params)
108
+ redirect_url = _REDIRECT_URL + "?" + redirect_query
109
+ url_params = {
110
+ "scope": "login",
111
+ "app_id": _APP_ID,
112
+ "redirect_url": redirect_url,
113
+ "state": state,
114
+ }
115
+ url_query = urlencode(url_params)
116
+ auth_url = _AUTH_URL + "?" + url_query
117
+
118
+ print_message(texts.get("login_prompt_no_browser"))
119
+ print_message("")
120
+ print_message(auth_url)
121
+
122
+ try:
123
+ input_func = raw_input
124
+ except NameError:
125
+ input_func = input
126
+
127
+ user_input = input_func(texts.get("login_prompt_code_no_browser"))
128
+ token = json.loads(base64.b64decode(user_input))
129
+ cred = oauth.get_temp_cred(token["accessToken"], token["site"])
130
+ return token, cred
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ import os
3
+
4
+ from tccli import oauth
5
+ from tccli.plugins.auth import texts
6
+
7
+
8
+ def logout_command_entrypoint(args, parsed_globals):
9
+ language = parsed_globals.get("language")
10
+ if not language:
11
+ language = "zh-CN"
12
+ texts.set_lang(language)
13
+
14
+ profile = parsed_globals.get("profile", "default")
15
+ if not profile:
16
+ profile = "default"
17
+
18
+ cred_path = oauth.cred_path_of_profile(profile)
19
+ if os.path.exists(cred_path):
20
+ os.remove(cred_path)
21
+ print(texts.get("logout") % cred_path)
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ _lang = "zh-CN"
3
+
4
+ texts = {
5
+ "zh-CN": {
6
+ "login_prompt": "您的浏览器已打开, 请根据提示完成登录",
7
+ "login_prompt_no_browser": "在浏览器中转到以下链接, 并根据提示完成登录:",
8
+ "login_prompt_code_no_browser": "完成后,输入浏览器中提供的验证码:",
9
+ "login_failed_due_to_no_browser": "无法打开浏览器, 请尝试添加 '--browser no' 选项",
10
+ "login_success": "登陆成功, 密钥凭证已被写入: %s",
11
+ "logout": "登出成功, 密钥凭证已被删除: %s",
12
+ },
13
+ "en-US": {
14
+ "login_prompt": "Your browser is open, please complete the login according to the prompts",
15
+ "login_prompt_no_browser": "Go to the following link in your browser, and complete the sign-in prompts:",
16
+ "login_prompt_code_no_browser": "Once finished, enter the verification code provided in your browser:",
17
+ "login_failed_due_to_no_browser": "Failed to launch browser, please try option '--browser no'",
18
+ "login_success": "Login succeed, credential has been written to %s",
19
+ "logout": "Logout succeed, credential has been removed: %s",
20
+ }
21
+ }
22
+
23
+
24
+ def set_lang(lang):
25
+ global _lang
26
+ _lang = lang
27
+
28
+
29
+ def get(key):
30
+ return texts[_lang][key]