lamda 7.73__tar.gz → 7.76__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. {lamda-7.73 → lamda-7.76}/PKG-INFO +5 -5
  2. {lamda-7.73 → lamda-7.76}/README.md +2 -7
  3. {lamda-7.73 → lamda-7.76}/lamda/__init__.py +1 -1
  4. {lamda-7.73 → lamda-7.76}/lamda/client.py +189 -1
  5. {lamda-7.73 → lamda-7.76}/lamda/rpc/services.proto +1 -0
  6. {lamda-7.73 → lamda-7.76}/lamda.egg-info/PKG-INFO +5 -5
  7. {lamda-7.73 → lamda-7.76}/lamda.egg-info/requires.txt +3 -3
  8. {lamda-7.73 → lamda-7.76}/setup.py +4 -4
  9. {lamda-7.73 → lamda-7.76}/lamda/bcast.proto +0 -0
  10. {lamda-7.73 → lamda-7.76}/lamda/const.py +0 -0
  11. {lamda-7.73 → lamda-7.76}/lamda/exceptions.py +0 -0
  12. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/any.proto +0 -0
  13. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/api.proto +0 -0
  14. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/compiler/plugin.proto +0 -0
  15. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/descriptor.proto +0 -0
  16. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/duration.proto +0 -0
  17. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/empty.proto +0 -0
  18. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/field_mask.proto +0 -0
  19. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/source_context.proto +0 -0
  20. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/struct.proto +0 -0
  21. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/timestamp.proto +0 -0
  22. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/type.proto +0 -0
  23. {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/wrappers.proto +0 -0
  24. {lamda-7.73 → lamda-7.76}/lamda/rpc/application.proto +0 -0
  25. {lamda-7.73 → lamda-7.76}/lamda/rpc/debug.proto +0 -0
  26. {lamda-7.73 → lamda-7.76}/lamda/rpc/file.proto +0 -0
  27. {lamda-7.73 → lamda-7.76}/lamda/rpc/policy.proto +0 -0
  28. {lamda-7.73 → lamda-7.76}/lamda/rpc/proxy.proto +0 -0
  29. {lamda-7.73 → lamda-7.76}/lamda/rpc/settings.proto +0 -0
  30. {lamda-7.73 → lamda-7.76}/lamda/rpc/shell.proto +0 -0
  31. {lamda-7.73 → lamda-7.76}/lamda/rpc/status.proto +0 -0
  32. {lamda-7.73 → lamda-7.76}/lamda/rpc/storage.proto +0 -0
  33. {lamda-7.73 → lamda-7.76}/lamda/rpc/types.proto +0 -0
  34. {lamda-7.73 → lamda-7.76}/lamda/rpc/uiautomator.proto +0 -0
  35. {lamda-7.73 → lamda-7.76}/lamda/rpc/util.proto +0 -0
  36. {lamda-7.73 → lamda-7.76}/lamda/rpc/wifi.proto +0 -0
  37. {lamda-7.73 → lamda-7.76}/lamda/types.py +0 -0
  38. {lamda-7.73 → lamda-7.76}/lamda.egg-info/SOURCES.txt +0 -0
  39. {lamda-7.73 → lamda-7.76}/lamda.egg-info/dependency_links.txt +0 -0
  40. {lamda-7.73 → lamda-7.76}/lamda.egg-info/not-zip-safe +0 -0
  41. {lamda-7.73 → lamda-7.76}/lamda.egg-info/top_level.txt +0 -0
  42. {lamda-7.73 → lamda-7.76}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lamda
3
- Version: 7.73
3
+ Version: 7.76
4
4
  Summary: Android reverse engineering & automation framework (Client API)
5
5
  Home-page: https://github.com/firerpa/lamda
6
6
  Author: rev1si0n
@@ -12,10 +12,10 @@ Classifier: Intended Audience :: Science/Research
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Operating System :: Android
14
14
  Classifier: Topic :: Security
15
- Requires-Python: >=3.6,<=3.12
16
- Requires-Dist: grpcio-tools<1.60.0,>=1.35.0
17
- Requires-Dist: grpc-interceptor<=0.15.2,>=0.13.0
18
- Requires-Dist: grpcio<1.60.0,>=1.35.0
15
+ Requires-Python: >=3.6,<3.13
16
+ Requires-Dist: grpcio-tools<=1.68.0,>=1.35.0
17
+ Requires-Dist: grpc-interceptor<=0.15.4,>=0.13.0
18
+ Requires-Dist: grpcio<=1.68.0,>=1.35.0
19
19
  Requires-Dist: cryptography>=35.0.0
20
20
  Requires-Dist: msgpack>=1.0.0
21
21
  Requires-Dist: asn1crypto<2,>=1.0.0
@@ -12,11 +12,11 @@
12
12
  <img src="https://img.shields.io/github/v/release/rev1si0n/lamda" />
13
13
  </p>
14
14
 
15
- <p align="center"><a href="https://github.com/rev1si0n/lamda/wiki">使用文档</a> | <a href="https://t.me/lamda_dev">TELEGRAM</a> | <a href="https://lamda.run/join/qq">QQ 群组</a> | <a href="https://github.com/rev1si0n/lamda/blob/HEAD/CHANGELOG.txt">更新历史</a></p>
15
+ <p align="center"><a href="https://device-farm.com/doc/index.html">使用文档</a> | <a href="https://t.me/lamda_dev">TELEGRAM</a> | <a href="https://lamda.run/join/qq">QQ 群组</a> | <a href="https://github.com/rev1si0n/lamda/blob/HEAD/CHANGELOG.txt">更新历史</a></p>
16
16
 
17
17
  智能机的崛起,传统网页端的普及度也开始显著减弱,数据与应用正加速向移动端转移。越来越多的人选择通过智能手机和平板等移动设备来获取信息和服务。随着移动设备的普及,用户享受到更便捷、更即时的访问体验,传统的网页内容消费模式面临重新审视。与此同时,数据采集的技术也亟需适应这一趋势。过去,许多数据采集工具专注于网页内容,但在移动端环境中,尤其是在移动端封闭的黑盒中,现今的常规采集技术也面临着新的挑战。LAMDA 的诞生,为这一切创造了可能。
18
18
 
19
- LAMDA 是一个**安卓领域的集大成者框架**,设计为减少**安全分析**及**应用测试**工作的时间和琐碎问题,为**移动端RPA数据采集**提供稳定的解决方案,以**编程化**的**接口**替代大量手动操作,**易部署**,没有那些复杂花哨不跨平台的安装流程,你所需要的能力他大概率能做到并且做的更好。他并不是一个单一功能的框架,他是集 Appium、uiautomator **自动化**的超集同时具备**逆向**领域如 **Hook** **抓包** **证书安装** **组网** **API跟踪** **手机自控** 等等各种能力的框架。为了让你大概了解它的用处:你是否会在手机上安装各类代理、插件或者点来点去的设置来完成你的工作?你是否要在异地操作远在千里之外的手机?你是否有编程控制手机的需求?是否还在某些云手机厂商那里购买昂贵的 **IP切换**、**远程ADB调试**、**RPA自动化**甚至连 **logcat 日志** 都要付费的服务?如果有,那么对了,只需一个 LAMDA 即可解决所有问题。并且,他更注重**分布式**,事实上,你可以在一台公网服务器上管理散布在世界各地各种网络环境中的设备。当然,LAMDA 可以做到的远不止于此,你可以阅读使用文档尽情探索他的所有能力。
19
+ LAMDA 是一个**安卓领域的集大成者**,设计为减少**安全分析**及**应用测试**工作的时间和琐碎问题,为**移动端RPA数据采集**提供稳定的解决方案,以**编程化**的**接口**替代大量手动操作,**易部署**,没有那些复杂花哨不跨平台的安装流程,你所需要的能力他大概率能做到并且做的更好。他并不是一个单一功能的框架,他是集 Appium、uiautomator **自动化**的超集同时具备**逆向**领域如 **Hook** **抓包** **证书安装** **组网** **API跟踪** **手机自控** 等等各种能力的框架。为了让你大概了解它的用处:你是否会在手机上安装各类代理、插件或者点来点去的设置来完成你的工作?你是否要在异地操作远在千里之外的手机?你是否有编程控制手机的需求?是否还在某些云手机厂商那里购买昂贵的 **IP切换**、**远程ADB调试**、**RPA自动化**甚至连 **logcat 日志** 都要付费的服务?如果有,那么对了,只需一个 LAMDA 即可解决所有问题。并且,他更注重**分布式**,事实上,你可以在一台公网服务器上管理散布在世界各地各种网络环境中的设备。当然,LAMDA 可以做到的远不止于此,你可以阅读使用文档尽情探索他的所有能力。
20
20
 
21
21
  <p align="center"><b>长期维护及更新,质量稳定,安全可靠,生产环境可用<br>现稳定应用于多个外部大型系统,包括自动化取证,云平台,数据采集,涉诈应用分析系统等<br>本框架已稳定运行于各种数据生产环境五年以上</b></p>
22
22
 
@@ -33,11 +33,6 @@ LAMDA 是一个**安卓领域的集大成者框架**,设计为减少**安全
33
33
 
34
34
  <p align="center">LAMDA 提供多达 160 条编程 API 接口,让你可以对安卓设备进行无微不至的管理和操作,提供了包括命令执行,系统设置,系统状态,应用相关,自动化相关,代理以及文件等十几个大类的接口。同时提供了封装完整的 Python 库让你可以快速上手使用。</p>
35
35
 
36
- <p align="center">
37
- <img src="image/api.png" alt="动图演示" width="95%">
38
- </p>
39
-
40
-
41
36
  <h3><p align="center">简洁易用的远程桌面</p></h3>
42
37
 
43
38
  <p align="center">
@@ -2,4 +2,4 @@
2
2
  #
3
3
  # Distributed under MIT license.
4
4
  # See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5
- __version__ = "7.73"
5
+ __version__ = "7.76"
@@ -44,7 +44,9 @@ except (ImportError, AttributeError):
44
44
 
45
45
  from . import __version__
46
46
  from . types import AttributeDict, BytesIO
47
- from . exceptions import UnHandledException, DuplicateEntryError, InvalidArgumentError
47
+ from . exceptions import (UnHandledException, DuplicateEntryError,
48
+ InvalidArgumentError, UiObjectNotFoundException,
49
+ IllegalStateException)
48
50
  from . import exceptions
49
51
 
50
52
  handler = logging.StreamHandler()
@@ -63,6 +65,8 @@ __all__ = [
63
65
  "GproxyType",
64
66
  "GrantType",
65
67
  "Group",
68
+ "CustomOcrBackend",
69
+ "OcrEngine",
66
70
  "Key",
67
71
  "Keys",
68
72
  "KeyCode",
@@ -168,6 +172,18 @@ def center(b):
168
172
  y = int(b.top + (b.bottom - b.top)/2)
169
173
  return Point(x=x, y=y)
170
174
 
175
+ def contain(a, b):
176
+ return all([b.top >= a.top,
177
+ b.left >= a.left,
178
+ b.bottom <= a.bottom,
179
+ b.right <= a.right])
180
+
181
+ def equal(a, b):
182
+ return all([b.top == a.top,
183
+ b.left == a.left,
184
+ b.bottom == a.bottom,
185
+ b.right == a.right])
186
+
171
187
  def corner(b, position):
172
188
  ca, cb = position.split("-")
173
189
  return Point(x=getattr(b, cb),
@@ -248,6 +264,8 @@ FindImageArea = protos.FindImageArea
248
264
 
249
265
  Bound.center = center
250
266
  Bound.corner = corner
267
+ Bound.__contains__ = contain
268
+ Bound.__eq__ = equal
251
269
 
252
270
 
253
271
  def load_proto(name):
@@ -267,6 +285,13 @@ def Selector(**kwargs):
267
285
  return sel
268
286
 
269
287
 
288
+ class CustomOcrBackend(object):
289
+ def __init__(self, *args, **kwargs):
290
+ raise NotImplementedError
291
+ def ocr(self, image):
292
+ raise NotImplementedError
293
+
294
+
270
295
  class BaseCryptor(object):
271
296
  def __str__(self):
272
297
  return "{}".format(self.__class__.__name__)
@@ -1100,6 +1125,11 @@ class ApplicationStub(BaseServiceStub):
1100
1125
  app = self.__call__(top.packageName)
1101
1126
  app.activity = top.activity
1102
1127
  return app
1128
+ def get_application_by_name(self, name, user=0):
1129
+ req = protos.String(value=name)
1130
+ r = self.stub.getIdentifierByLabel(req)
1131
+ app = self.__call__(r.value, user=user)
1132
+ return app
1103
1133
  def enumerate_running_processes(self):
1104
1134
  """
1105
1135
  列出设备上所有正在运行的安卓应用进程
@@ -1804,6 +1834,140 @@ class WifiStub(BaseServiceStub):
1804
1834
  raise NotImplementedError
1805
1835
 
1806
1836
 
1837
+ class OcrOperator(object):
1838
+ def __init__(self, device, elements=None,
1839
+ **kwargs):
1840
+ self.elements = elements
1841
+ self.index = kwargs.pop("index", 0)
1842
+ self.func, self.rule = kwargs.popitem()
1843
+ self.match = getattr(self, self.func)
1844
+ self.device = device
1845
+ def text(self, item):
1846
+ return self.rule == item["text"]
1847
+ def textMatches(self, item):
1848
+ return bool(re.match(self.rule, item["text"],
1849
+ re.DOTALL))
1850
+ def textContains(self, item):
1851
+ return self.rule in item["text"]
1852
+ def find_target_item(self):
1853
+ m = [e for e in self.elements \
1854
+ if self.match(e)]
1855
+ o = (m and len(m) > self.index) != True
1856
+ return None if o else m[self.index]
1857
+ def find_item_or_throw(self):
1858
+ item = self.find_target_item()
1859
+ msg = "OcrSelector[{}={}]".format(self.func, self.rule)
1860
+ item or self.throw(UiObjectNotFoundException, msg)
1861
+ return item
1862
+ def find_cb(self, func, ret, *args):
1863
+ item = self.find_target_item()
1864
+ return func(item, *args) if item else ret
1865
+ def find_or_throw_cb(self, func, *args):
1866
+ item = self.find_item_or_throw()
1867
+ return func(item, *args)
1868
+ def throw(self, exception, *args):
1869
+ raise exception(*args)
1870
+ def _screenshot(self, item, quality):
1871
+ return self.device.screenshot(quality,
1872
+ bound=item["bound"])
1873
+ def _click(self, item):
1874
+ point = item["bound"].center()
1875
+ return self.device.click(point)
1876
+ def __str__(self):
1877
+ return "Ocr: {}={}".format(self.func, self.rule)
1878
+ __repr__ = __str__
1879
+ def exists(self):
1880
+ """
1881
+ OCR - 检查元素是否存在
1882
+ """
1883
+ return bool(self.find_target_item())
1884
+ def exist(self):
1885
+ """
1886
+ OCR - 检查元素是否存在
1887
+ """
1888
+ return self.exists()
1889
+ def click(self):
1890
+ """
1891
+ OCR - 点击元素(不存在则报错)
1892
+ """
1893
+ return self.find_or_throw_cb(self._click)
1894
+ def click_exists(self):
1895
+ """
1896
+ OCR - 点击元素(不存在将不会产生异常)
1897
+ """
1898
+ return self.find_cb(self._click, False)
1899
+ def click_exist(self):
1900
+ """
1901
+ OCR - 点击元素(不存在将不会产生异常)
1902
+ """
1903
+ return self.click_exists()
1904
+ def screenshot(self, quality=100):
1905
+ """
1906
+ OCR - 对元素进行截图
1907
+ """
1908
+ return self.find_or_throw_cb(self._screenshot,
1909
+ quality)
1910
+ def take_screenshot(self, quality=100):
1911
+ """
1912
+ OCR - 对元素进行截图
1913
+ """
1914
+ return self.screenshot(quality)
1915
+ def info(self):
1916
+ """
1917
+ OCR - 获取匹配元素的信息
1918
+ """
1919
+ item = self.find_item_or_throw()
1920
+ return item
1921
+
1922
+
1923
+ class OcrEngine(object):
1924
+ def __init__(self, service, *args,
1925
+ **kwargs):
1926
+ args = list(args)
1927
+ if type(service) == type:
1928
+ args.insert(0, service)
1929
+ service = "custom"
1930
+ func = getattr(self, "init_{}".format(service))
1931
+ func(*args, **kwargs)
1932
+ def init_paddleocr(self, *args, **kwargs):
1933
+ from paddleocr import PaddleOCR
1934
+ self._service = PaddleOCR(*args, **kwargs)
1935
+ self._ocr = self.ocr_paddleocr
1936
+ def init_easyocr(self, *args, **kwargs):
1937
+ from easyocr import Reader
1938
+ self._service = Reader(*args, **kwargs)
1939
+ self._ocr = self.ocr_easyocr
1940
+ def init_custom(self, service, *args, **kwargs):
1941
+ self._service = service(*args, **kwargs)
1942
+ self._ocr = self.ocr_custom
1943
+ def ocr_custom(self, image):
1944
+ result = self._service.ocr(image)
1945
+ return result
1946
+ def ocr_paddleocr(self, image):
1947
+ r = self._service.ocr(image)
1948
+ n = bool(r and r[0] and type(r[0][-1])==float)
1949
+ result = (r if n else r[0]) or []
1950
+ output = [[n[0], n[1][0], n[1][1]] for n in result]
1951
+ return output
1952
+ def ocr_easyocr(self, image):
1953
+ result = self._service.readtext(image)
1954
+ return result
1955
+ def ocr(self, screenshot):
1956
+ img = screenshot.getvalue()
1957
+ result = self._ocr(img) or []
1958
+ output = [self.format(*n) for n in result]
1959
+ return output
1960
+ def format(self, box, text, confidence):
1961
+ bound = Bound()
1962
+ bound.left = int(min(p[0] for p in box))
1963
+ bound.top = int(min(p[1] for p in box))
1964
+ bound.bottom = int(max(p[1] for p in box))
1965
+ bound.right = int(max(p[0] for p in box))
1966
+ info = dict(text=text, confidence=confidence,
1967
+ bound=bound)
1968
+ return info
1969
+
1970
+
1807
1971
  class Device(object):
1808
1972
  def __init__(self, host, port=65000,
1809
1973
  certificate=None,
@@ -1827,6 +1991,8 @@ class Device(object):
1827
1991
  interceptors = [ClientSessionMetadataInterceptor(session),
1828
1992
  GrpcRemoteExceptionInterceptor(),
1829
1993
  ClientLoggingInterceptor()]
1994
+ self._ocr = None
1995
+ self._ocr_img_quality = 75
1830
1996
  self.channel = grpc.intercept_channel(self._chan,
1831
1997
  *interceptors)
1832
1998
  self.session = session
@@ -1897,6 +2063,8 @@ class Device(object):
1897
2063
  return self.stub("Application").get_last_activities(count=count)
1898
2064
  def start_activity(self, **activity):
1899
2065
  return self.stub("Application").start_activity(**activity)
2066
+ def get_application_by_name(self, name):
2067
+ return self.stub("Application").get_application_by_name(name)
1900
2068
  def application(self, applicationId, user=0):
1901
2069
  return self.stub("Application")(applicationId, user=user)
1902
2070
  # 快速调用: Util
@@ -2045,6 +2213,26 @@ class Device(object):
2045
2213
  return self.stub("UiAutomator").device_info()
2046
2214
  def __call__(self, **kwargs):
2047
2215
  return self.stub("UiAutomator")(**kwargs)
2216
+ # OCR 功能扩展
2217
+ def ocr(self, index=0, **kwargs):
2218
+ if not isinstance(self._ocr, OcrEngine):
2219
+ raise IllegalStateException("Ocr engine is not setted up")
2220
+ if any(r not in ["text", "textContains", "textMatches"] \
2221
+ for r in kwargs.keys()):
2222
+ raise InvalidArgumentError("Only text* matches are supported")
2223
+ if len(kwargs) != 1:
2224
+ raise InvalidArgumentError("Only or at least one rule can be used")
2225
+ image = self.screenshot(self._ocr_img_quality)
2226
+ return OcrOperator(self,
2227
+ elements=self._ocr.ocr(image),
2228
+ index=index,
2229
+ **kwargs
2230
+ )
2231
+ def setup_ocr_backend(self, service, *args, quality=75,
2232
+ **kwargs):
2233
+ self._ocr_img_quality = quality
2234
+ self._ocr = OcrEngine(service, *args,
2235
+ **kwargs)
2048
2236
  # 日志打印
2049
2237
  def set_debug_log_enabled(self, enable):
2050
2238
  level = logging.DEBUG if enable else logging.WARN
@@ -49,6 +49,7 @@ service Application {
49
49
 
50
50
  rpc addToDozeModeWhiteList(ApplicationRequest) returns (Boolean) {}
51
51
  rpc removeFromDozeModeWhiteList(ApplicationRequest) returns (Boolean) {}
52
+ rpc getIdentifierByLabel(String) returns (String) {}
52
53
  }
53
54
 
54
55
  service Debug {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lamda
3
- Version: 7.73
3
+ Version: 7.76
4
4
  Summary: Android reverse engineering & automation framework (Client API)
5
5
  Home-page: https://github.com/firerpa/lamda
6
6
  Author: rev1si0n
@@ -12,10 +12,10 @@ Classifier: Intended Audience :: Science/Research
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Operating System :: Android
14
14
  Classifier: Topic :: Security
15
- Requires-Python: >=3.6,<=3.12
16
- Requires-Dist: grpcio-tools<1.60.0,>=1.35.0
17
- Requires-Dist: grpc-interceptor<=0.15.2,>=0.13.0
18
- Requires-Dist: grpcio<1.60.0,>=1.35.0
15
+ Requires-Python: >=3.6,<3.13
16
+ Requires-Dist: grpcio-tools<=1.68.0,>=1.35.0
17
+ Requires-Dist: grpc-interceptor<=0.15.4,>=0.13.0
18
+ Requires-Dist: grpcio<=1.68.0,>=1.35.0
19
19
  Requires-Dist: cryptography>=35.0.0
20
20
  Requires-Dist: msgpack>=1.0.0
21
21
  Requires-Dist: asn1crypto<2,>=1.0.0
@@ -1,6 +1,6 @@
1
- grpcio-tools<1.60.0,>=1.35.0
2
- grpc-interceptor<=0.15.2,>=0.13.0
3
- grpcio<1.60.0,>=1.35.0
1
+ grpcio-tools<=1.68.0,>=1.35.0
2
+ grpc-interceptor<=0.15.4,>=0.13.0
3
+ grpcio<=1.68.0,>=1.35.0
4
4
  cryptography>=35.0.0
5
5
  msgpack>=1.0.0
6
6
  asn1crypto<2,>=1.0.0
@@ -10,7 +10,7 @@ setuptools.setup(
10
10
  description = "Android reverse engineering & automation framework (Client API)",
11
11
  url = "https://github.com/firerpa/lamda",
12
12
  author = "rev1si0n",
13
- python_requires = ">=3.6,<=3.12",
13
+ python_requires = ">=3.6,<3.13",
14
14
  zip_safe = False,
15
15
  extras_require = {
16
16
  "full": ["frida>=16.0.0,<17.0.0"],
@@ -19,9 +19,9 @@ setuptools.setup(
19
19
  ],
20
20
  },
21
21
  install_requires= [
22
- "grpcio-tools>=1.35.0,<1.60.0",
23
- "grpc-interceptor>=0.13.0,<=0.15.2",
24
- "grpcio>=1.35.0,<1.60.0",
22
+ "grpcio-tools>=1.35.0,<=1.68.0",
23
+ "grpc-interceptor>=0.13.0,<=0.15.4",
24
+ "grpcio>=1.35.0,<=1.68.0",
25
25
  "cryptography>=35.0.0",
26
26
  "msgpack>=1.0.0",
27
27
  "asn1crypto>=1.0.0,<2",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes