serve_client.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. import base64
  2. import hashlib
  3. import json
  4. import os.path
  5. import re
  6. import requests
  7. from Crypto.Cipher import AES
  8. from tools.logger_handle import logger
  9. from tools.oss_client import oss_handle
  10. class ServerClient:
  11. def __init__(self, server_host, user_name, password):
  12. self.user_name = user_name
  13. self.password = password
  14. self.serve_host = server_host
  15. self.access_token = None
  16. self.headers = {
  17. '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',
  18. }
  19. self.login()
  20. def login(self):
  21. url = self.serve_host + '/auth/oauth2/token'
  22. reply = requests.post(url, params={
  23. 'username': self.user_name,
  24. 'password': self.encryption(self.password),
  25. 'grant_type': 'password',
  26. 'scope': 'server',
  27. 'client_id': 'knowledge',
  28. 'client_secret': 'knowledge'
  29. }, headers={'Content-Type': 'multipart/form-data',
  30. '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'})
  31. self.access_token = reply.json()['access_token']
  32. self.headers['Authorization'] = f'Bearer {self.access_token}'
  33. def decryption(self, hex_str, secret='anZz000000000000'):
  34. key_bytes = secret.encode('utf-8')
  35. iv = key_bytes
  36. base64_str = base64.b64encode(bytes.fromhex(hex_str)).decode('utf-8')
  37. cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
  38. decrypted = cipher.decrypt(base64.b64decode(base64_str))
  39. try:
  40. decoded = decrypted.decode('utf-8')
  41. except UnicodeDecodeError:
  42. decoded = decrypted.decode('utf-8', errors='ignore')
  43. # 清除控制字符(类似 JS 中的 [\u0000-\u001F\u007F-\u009F])
  44. cleaned = re.sub(r'[\x00-\x1F\x7F-\x9F]', ' ', decoded)
  45. try:
  46. return json.loads(cleaned)
  47. except json.JSONDecodeError:
  48. return cleaned.strip()
  49. def zero_pad(self, data, block_size=16):
  50. pad_len = block_size - (len(data) % block_size)
  51. if pad_len == 0:
  52. return data
  53. return data + b'\x00' * pad_len
  54. def encryption(self, payload, secret='a25vd2xlZGdl0000'.encode('utf-8')):
  55. data_bytes = payload.encode('utf-8')
  56. padded_data = self.zero_pad(data_bytes)
  57. cipher = AES.new(secret, AES.MODE_CBC, secret)
  58. encrypted = cipher.encrypt(padded_data)
  59. return encrypted.hex()
  60. def check_resp(self, resp):
  61. if resp.json()['code'] == -2:
  62. self.login()
  63. return True
  64. return False
  65. def download_file(self, file_info, storage_path):
  66. try:
  67. resp = requests.get(f'{self.serve_host}/mgr/document/dcLibrary/file/get/file/{file_info["id"]}',
  68. headers=self.headers)
  69. local_file_name = file_info['filePath'].replace('/', '_')
  70. with open(os.path.join(storage_path, local_file_name), 'wb') as f:
  71. f.write(resp.content)
  72. with open(os.path.join(storage_path, local_file_name + '.metadata'), 'w', encoding='utf-8') as f:
  73. f.write(json.dumps({
  74. 'serve': oss_handle.service,
  75. 'access_key': oss_handle.access_key,
  76. 'secret_key': oss_handle.secret_key,
  77. 'file_id': file_info["id"],
  78. 'bucket_name': file_info['bucketName'],
  79. 'md5': self.get_file_md5(os.path.join(storage_path, local_file_name)),
  80. 'file_name': file_info['name'],
  81. 'oss_path': file_info['filePath'],
  82. 'update_time': file_info['updateTime']
  83. }))
  84. except Exception as e:
  85. logger.exception(e)
  86. return False
  87. return True
  88. def upload_file(self, file_path):
  89. try:
  90. with open(f'{file_path}.metadata', 'r', encoding='utf-8') as f:
  91. file_metadata = json.loads(f.read())
  92. file_id = file_metadata['file_id']
  93. files = [('file', (file_metadata['file_name'], open(file_path, 'rb'),
  94. 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'))]
  95. resp = requests.post(
  96. f'{self.serve_host}/mgr/document/dcLibrary/saveByPython/{file_id}',
  97. headers=self.headers,
  98. files=files,
  99. data={}
  100. )
  101. if self.check_resp(resp):
  102. resp = requests.post(
  103. f'{self.serve_host}/mgr/document/dcLibrary/saveByPython/{file_id}',
  104. headers=self.headers,
  105. files=files,
  106. data={})
  107. if resp.json()['code'] == 0:
  108. return True
  109. else:
  110. logger.error(resp.json())
  111. return False
  112. except Exception as e:
  113. logger.exception(e)
  114. return False
  115. @staticmethod
  116. def get_file_md5(file_path):
  117. md5 = hashlib.md5()
  118. with open(file_path, 'rb') as f:
  119. # 分块读取以支持大文件
  120. while chunk := f.read(8192):
  121. md5.update(chunk)
  122. return md5.hexdigest()
  123. @staticmethod
  124. def load_metadata(local_path):
  125. with open(f'{local_path}.metadata', 'r', encoding='utf-8') as f:
  126. file_metadata = json.loads(f.read())
  127. return file_metadata
  128. def get_file_info(self, file_id):
  129. '''
  130. {'createTime': '2025-06-03 15:57:37',
  131. 'updateTime': '2025-06-16 11:17:52',
  132. 'createById': '1',
  133. 'createBy': '超级管理员',
  134. 'updateBy': '超级管理员',
  135. 'id': 'c5a8f3d5811e572265501eeaf6d8b1cf',
  136. 'filePath': 'ten_1/lujie/document-mgr/SYG测试文库/test2.docx/2025/06/16/2025-06-161119224319835017216-c9b17214ea4144cf922f2fbfc0cdf70d.office_doc.docx',
  137. 'bucketName': 'document-mgr',
  138. 'name': 'test2.docx',
  139. 'shareRole': 'user',
  140. 'size': 26424,
  141. 'parentId': '6b79a0c8359b89653b95a14ad08b4954',
  142. 'type': 'office_doc',
  143. 'orderId': 12, 'delFlag': False,
  144. 'pathId': ['6b79a0c8359b89653b95a14ad08b4954'],
  145. 'knowledgeId': '6b79a0c8359b89653b95a14ad08b4954',
  146. 'tenantId': '1', 'commentable': True, '
  147. readNotify': True, 'nameSuffix': 'docx',
  148. 'fileStatus': 'NORMAL'}
  149. :param file_id:
  150. :return:
  151. '''
  152. try:
  153. resp = requests.get(f'{self.serve_host}/mgr/document/no/auth/dcLibrary/info/{file_id}',
  154. headers=self.headers)
  155. if not self.check_resp(resp):
  156. resp = requests.get(f'{self.serve_host}/mgr/document/no/auth/dcLibrary/info/{file_id}',
  157. headers=self.headers)
  158. if not resp.json()['data']:
  159. return 2
  160. return self.decryption(resp.json()['data'])
  161. except Exception as e:
  162. logger.exception(e)
  163. return False
  164. if __name__ == '__main__':
  165. client = ServerClient('http://172.10.3.71:10001', 'admin', '123456')
  166. # client = ServerClient('admin', 'jxkj123456')
  167. # client.download_file(
  168. # {'file_name': 'test.docx', 'file_id': 'c5a8f3d5811e572265501eeaf6d8b1cf', 'bucket_name': 'aaa', }, '')
  169. res = client.get_file_info(r'585ec718900fa82ce3d35d515c9d8a4b')
  170. res = client.decryption("")
  171. for row in res['data']:
  172. print(row)
  173. a = {'createTime': '2025-06-13 11:48:35', 'updateTime': '2025-06-13 14:01:48', 'createById': '1',
  174. 'createBy': '超级管理员', 'updateBy': '超级管理员', 'id': 'c04b39ebfa8141746c20b88c7417f972',
  175. 'filePath': 'ten_1/2_2/document-mgr/法律法规/新建文件.docx/2025/06/13/2025-06-131118178409944354816-e251bced912f4d68bc50d80a33cbbd5d.office_doc.docx',
  176. 'bucketName': 'document-mgr', 'name': '新建文件.docx', 'shareRole': 'user', 'size': 29527,
  177. 'parentId': 'a3d958a6bba28357757ca20c87af9954', 'type': 'office_doc', 'orderId': 24, 'delFlag': False,
  178. 'pathId': ['a3d958a6bba28357757ca20c87af9954'], 'knowledgeId': 'a3d958a6bba28357757ca20c87af9954',
  179. 'tenantId': '1', 'commentable': True, 'readNotify': True, 'nameSuffix': 'docx', 'fileStatus': 'NORMAL',
  180. 'dcIdentifying': [
  181. {'id': '1', 'identifyingName': '文档分享', 'name': '文档分享', 'identifyingKey': 'document_share',
  182. 'identifyingType': 'document', 'isSelect': False, 'possessorIs': False},
  183. {'id': '11', 'identifyingName': '文库删除', 'name': '文库删除', 'identifyingKey': 'library_delete',
  184. 'identifyingType': 'library', 'isSelect': False, 'possessorIs': False},
  185. {'id': '12', 'identifyingName': '文库编辑', 'name': '文库编辑', 'identifyingKey': 'library_update',
  186. 'identifyingType': 'library', 'isSelect': False, 'possessorIs': False},
  187. {'id': '13', 'identifyingName': '文库下载', 'name': '文库下载', 'identifyingKey': 'library_down',
  188. 'identifyingType': 'library', 'isSelect': False, 'possessorIs': False},
  189. {'id': '5', 'identifyingName': '文档删除', 'name': '文档删除', 'identifyingKey': 'document_delete',
  190. 'identifyingType': 'document', 'isSelect': False, 'possessorIs': False},
  191. {'id': '6', 'identifyingName': '新建文档', 'name': '新建文档', 'identifyingKey': 'document_add',
  192. 'identifyingType': 'document', 'isSelect': False, 'possessorIs': False},
  193. {'id': '7', 'identifyingName': '文档下载', 'name': '文档下载', 'identifyingKey': 'document_down',
  194. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False},
  195. {'id': '8', 'identifyingName': '文档编辑', 'name': '文档编辑', 'identifyingKey': 'document_update',
  196. 'identifyingType': 'document', 'isSelect': False, 'possessorIs': False},
  197. {'id': '9', 'identifyingName': '文档移动', 'name': '文档移动', 'identifyingKey': 'document_move',
  198. 'identifyingType': 'document', 'isSelect': False, 'possessorIs': False},
  199. {'id': '14', 'identifyingName': '文档消息设置', 'name': '文档消息设置',
  200. 'identifyingKey': 'document_remind_settings', 'identifyingType': 'document', 'isSelect': False,
  201. 'possessorIs': False}, {'id': '15', 'identifyingName': '文库权限设置', 'name': '文库权限设置',
  202. 'identifyingKey': 'library_auth_settings', 'identifyingType': 'document',
  203. 'isSelect': False, 'possessorIs': False},
  204. {'id': '3', 'identifyingName': '文库消息设置', 'name': '文库消息设置',
  205. 'identifyingKey': 'library_remind_settings', 'identifyingType': 'library', 'isSelect': False,
  206. 'possessorIs': False}, {'id': '4', 'identifyingName': '文档权限设置', 'name': '文档权限设置',
  207. 'identifyingKey': 'document_auth_settings', 'identifyingType': 'document',
  208. 'isSelect': False, 'possessorIs': False},
  209. {'id': '1', 'identifyingName': '文档分享', 'name': '', 'identifyingKey': 'document_share',
  210. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
  211. {'id': '10', 'identifyingName': '查看', 'name': '', 'identifyingKey': 'view',
  212. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
  213. {'id': '11', 'identifyingName': '文库删除', 'name': '', 'identifyingKey': 'library_delete',
  214. 'identifyingType': 'library', 'isSelect': True, 'possessorIs': False, 'select': True},
  215. {'id': '12', 'identifyingName': '文库编辑', 'name': '', 'identifyingKey': 'library_update',
  216. 'identifyingType': 'library', 'isSelect': True, 'possessorIs': False, 'select': True},
  217. {'id': '13', 'identifyingName': '文库下载', 'name': '', 'identifyingKey': 'library_down',
  218. 'identifyingType': 'library', 'isSelect': True, 'possessorIs': False, 'select': True},
  219. {'id': '14', 'identifyingName': '文档消息设置', 'name': '', 'identifyingKey': 'document_remind_settings',
  220. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
  221. {'id': '15', 'identifyingName': '文库权限设置', 'name': '', 'identifyingKey': 'library_auth_settings',
  222. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
  223. {'id': '2', 'identifyingName': '文库转移项目', 'name': '', 'identifyingKey': 'library_transfer',
  224. 'identifyingType': 'library', 'isSelect': True, 'possessorIs': True, 'select': True},
  225. {'id': '3', 'identifyingName': '文库消息设置', 'name': '', 'identifyingKey': 'library_remind_settings',
  226. 'identifyingType': 'library', 'isSelect': True, 'possessorIs': False, 'select': True},
  227. {'id': '4', 'identifyingName': '文档权限设置', 'name': '', 'identifyingKey': 'document_auth_settings',
  228. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
  229. {'id': '5', 'identifyingName': '文档删除', 'name': '', 'identifyingKey': 'document_delete',
  230. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
  231. {'id': '6', 'identifyingName': '新建文档', 'name': '', 'identifyingKey': 'document_add',
  232. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
  233. {'id': '7', 'identifyingName': '文档下载', 'name': '', 'identifyingKey': 'document_down',
  234. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
  235. {'id': '8', 'identifyingName': '文档编辑', 'name': '', 'identifyingKey': 'document_update',
  236. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True},
  237. {'id': '9', 'identifyingName': '文档移动', 'name': '', 'identifyingKey': 'document_move',
  238. 'identifyingType': 'document', 'isSelect': True, 'possessorIs': False, 'select': True}], 'share': False}
  239. # access_token = client.login()
  240. # print(requests.post('http://120.195.49.22:7215/mgr/document/dcLibrary/knowledges?size=1000&current=1', headers={
  241. # 'authorization': f'Bearer {access_token}'}).json())