serve_client.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import base64
  2. import hashlib
  3. import json
  4. import os.path
  5. import re
  6. import sys
  7. import tkinter
  8. from tkinter import messagebox
  9. import requests
  10. from Crypto.Cipher import AES
  11. from config import *
  12. from tools.logger_handle import logger
  13. class ServerClient:
  14. def __init__(self, server_host, user_name, password):
  15. self.user_name = user_name
  16. self.password = password
  17. self.serve_host = server_host
  18. self.access_token = None
  19. self.login_reply = None
  20. self.headers = {
  21. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
  22. }
  23. self.login()
  24. def login(self):
  25. url = self.serve_host + '/auth/oauth2/token'
  26. reply = requests.post(url, params={
  27. 'username': self.user_name,
  28. 'password': self.encryption(self.password),
  29. 'grant_type': 'password',
  30. 'scope': 'server',
  31. 'client_id': 'knowledge',
  32. 'client_secret': 'knowledge'
  33. }, headers={'Content-Type': 'multipart/form-data',
  34. 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36'})
  35. reply_data = reply.json()
  36. logger.info(url, self.user_name, self.password)
  37. if 'access_token' not in reply_data:
  38. self.show_error_window(reply_data['msg'])
  39. self.access_token = reply.json()['access_token']
  40. self.login_reply = reply.json()
  41. self.headers['Authorization'] = f'Bearer {self.access_token}'
  42. def show_error_window(self, message):
  43. root = tkinter.Tk()
  44. root.withdraw()
  45. root.attributes('-topmost', True)
  46. messagebox.showerror("登录失败", message)
  47. root.destroy()
  48. sys.exit(0)
  49. def decryption(self, hex_str, secret='anZz000000000000'):
  50. key_bytes = secret.encode('utf-8')
  51. iv = key_bytes
  52. base64_str = base64.b64encode(bytes.fromhex(hex_str)).decode('utf-8')
  53. cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
  54. decrypted = cipher.decrypt(base64.b64decode(base64_str))
  55. try:
  56. decoded = decrypted.decode('utf-8')
  57. except UnicodeDecodeError:
  58. decoded = decrypted.decode('utf-8', errors='ignore')
  59. # 清除控制字符(类似 JS 中的 [\u0000-\u001F\u007F-\u009F])
  60. cleaned = re.sub(r'[\x00-\x1F\x7F-\x9F]', ' ', decoded)
  61. try:
  62. return json.loads(cleaned)
  63. except json.JSONDecodeError:
  64. return cleaned.strip()
  65. def zero_pad(self, data, block_size=16):
  66. pad_len = block_size - (len(data) % block_size)
  67. if pad_len == 0:
  68. return data
  69. return data + b'\x00' * pad_len
  70. def encryption(self, payload, secret='a25vd2xlZGdl0000'.encode('utf-8')):
  71. data_bytes = payload.encode('utf-8')
  72. padded_data = self.zero_pad(data_bytes)
  73. cipher = AES.new(secret, AES.MODE_CBC, secret)
  74. encrypted = cipher.encrypt(padded_data)
  75. return encrypted.hex()
  76. def get_base_path(self):
  77. url = self.serve_host + '/mgr/document/dcLibrary/knowledges/owner?size=1000&current=1'
  78. reply = requests.get(url, headers=self.headers)
  79. reply_data = reply.json()
  80. if reply_data.get('code') != 0:
  81. return []
  82. data = self.decryption(reply_data['data'])
  83. return data.get('records', [])
  84. def get_folder_by_id(self, _id):
  85. url = f'{self.serve_host}/mgr/document/dcLibrary/tree?id={_id}'
  86. self.headers['documentid'] = _id
  87. reply = requests.get(url, headers=self.headers)
  88. reply_data = reply.json()
  89. if reply_data.get('code') != 0:
  90. return []
  91. data = self.decryption(reply_data['data'])
  92. return data.get('data', [])
  93. def check_resp(self, resp):
  94. if resp.json()['code'] == -2:
  95. self.login()
  96. return True
  97. return False
  98. def download_file(self, file_info, storage_path):
  99. try:
  100. resp = requests.get(f'{self.serve_host}/mgr/document/dcLibrary/file/get/file/{file_info["id"]}',
  101. headers=self.headers)
  102. local_file_name = file_info['filePath'].replace('/', '_')
  103. with open(os.path.join(storage_path, local_file_name), 'wb') as f:
  104. f.write(resp.content)
  105. with open(os.path.join(storage_path, local_file_name + '.metadata'), 'w', encoding='utf-8') as f:
  106. f.write(json.dumps({
  107. 'file_id': file_info["id"],
  108. 'bucket_name': file_info['bucketName'],
  109. 'md5': self.get_file_md5(os.path.join(storage_path, local_file_name)),
  110. 'file_name': file_info['name'],
  111. 'oss_path': file_info['filePath'],
  112. 'update_time': file_info['updateTime']
  113. }))
  114. except Exception as e:
  115. logger.exception(e)
  116. return False
  117. return True
  118. def upload_file(self, file_path):
  119. try:
  120. with open(f'{file_path}.metadata', 'r', encoding='utf-8') as f:
  121. file_metadata = json.loads(f.read())
  122. file_id = file_metadata['file_id']
  123. files = [('file', (file_metadata['file_name'], open(file_path, 'rb'),
  124. 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'))]
  125. resp = requests.post(
  126. f'{self.serve_host}/mgr/document/dcLibrary/saveByPython/{file_id}',
  127. headers=self.headers,
  128. files=files,
  129. data={}
  130. )
  131. if self.check_resp(resp):
  132. resp = requests.post(
  133. f'{self.serve_host}/mgr/document/dcLibrary/saveByPython/{file_id}',
  134. headers=self.headers,
  135. files=files,
  136. data={})
  137. if resp.json()['code'] == 0:
  138. return True
  139. else:
  140. logger.error(resp.json())
  141. return False
  142. except Exception as e:
  143. logger.exception(e)
  144. return False
  145. @staticmethod
  146. def get_file_md5(file_path):
  147. md5 = hashlib.md5()
  148. with open(file_path, 'rb') as f:
  149. # 分块读取以支持大文件
  150. while chunk := f.read(8192):
  151. md5.update(chunk)
  152. return md5.hexdigest()
  153. @staticmethod
  154. def load_metadata(local_path):
  155. with open(f'{local_path}.metadata', 'r', encoding='utf-8') as f:
  156. file_metadata = json.loads(f.read())
  157. return file_metadata
  158. def create_cloud_file(self, local_file='D:/bussion/法律法规/道路交通安全法.docx',
  159. folder_id='5b091f1007c880528bd913530987d5e5'):
  160. payload = {'module': '/jvs-knowledge-ui/jvs-knowledge-import/'}
  161. files = [
  162. ('file', (os.path.basename(local_file), open(local_file, 'rb'),
  163. 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'))]
  164. resp = requests.post(f'{TARGET_URL}/mgr/document/dcLibrary/upload/{folder_id}',
  165. headers=self.headers, data=payload, files=files)
  166. if resp.json().get('code') == 0:
  167. return True
  168. else:
  169. return False
  170. def get_folder_tree(self):
  171. resp = requests.get(f'{TARGET_URL}/mgr/document/dcLibrary/tree/myFolder', headers=self.headers)
  172. if resp.json().get('code') == 0:
  173. return self.decryption(resp.json()['data'])
  174. else:
  175. return []
  176. def get_template_file_info(self, file_id):
  177. try:
  178. resp = requests.get(f'{TARGET_URL}/mgr/document/dcLibrary/template/get/{file_id}',
  179. headers=self.headers)
  180. if resp.json().get('code') == 0:
  181. return self.decryption(resp.json()['data'])
  182. return False
  183. except Exception as e:
  184. logger.error('获取模板信息出错')
  185. logger.exception(e)
  186. return False
  187. def download_template(self, url, file_path):
  188. try:
  189. resp = requests.get(url)
  190. with open(file_path, 'wb') as f:
  191. f.write(resp.content)
  192. return True
  193. except Exception as e:
  194. logger.error('下载模板文件出错')
  195. logger.exception(e)
  196. return False
  197. def get_file_info(self, file_id):
  198. '''
  199. :param file_id:
  200. :return:
  201. '''
  202. logger.info(self.headers)
  203. try:
  204. resp = requests.get(f'{self.serve_host}/mgr/document/no/auth/dcLibrary/info/{file_id}',
  205. headers=self.headers)
  206. if not self.check_resp(resp):
  207. resp = requests.get(f'{self.serve_host}/mgr/document/no/auth/dcLibrary/info/{file_id}',
  208. headers=self.headers)
  209. if not resp.json()['data']:
  210. return False
  211. return self.decryption(resp.json()['data'])
  212. except Exception as e:
  213. logger.exception(e)
  214. return False
  215. server_client = ServerClient(TARGET_URL, args['username'], args['password'])