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.
- {lamda-7.73 → lamda-7.76}/PKG-INFO +5 -5
- {lamda-7.73 → lamda-7.76}/README.md +2 -7
- {lamda-7.73 → lamda-7.76}/lamda/__init__.py +1 -1
- {lamda-7.73 → lamda-7.76}/lamda/client.py +189 -1
- {lamda-7.73 → lamda-7.76}/lamda/rpc/services.proto +1 -0
- {lamda-7.73 → lamda-7.76}/lamda.egg-info/PKG-INFO +5 -5
- {lamda-7.73 → lamda-7.76}/lamda.egg-info/requires.txt +3 -3
- {lamda-7.73 → lamda-7.76}/setup.py +4 -4
- {lamda-7.73 → lamda-7.76}/lamda/bcast.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/const.py +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/exceptions.py +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/any.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/api.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/compiler/plugin.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/descriptor.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/duration.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/empty.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/field_mask.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/source_context.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/struct.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/timestamp.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/type.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/google/protobuf/wrappers.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/application.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/debug.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/file.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/policy.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/proxy.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/settings.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/shell.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/status.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/storage.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/types.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/uiautomator.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/util.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/rpc/wifi.proto +0 -0
- {lamda-7.73 → lamda-7.76}/lamda/types.py +0 -0
- {lamda-7.73 → lamda-7.76}/lamda.egg-info/SOURCES.txt +0 -0
- {lamda-7.73 → lamda-7.76}/lamda.egg-info/dependency_links.txt +0 -0
- {lamda-7.73 → lamda-7.76}/lamda.egg-info/not-zip-safe +0 -0
- {lamda-7.73 → lamda-7.76}/lamda.egg-info/top_level.txt +0 -0
- {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.
|
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
|
16
|
-
Requires-Dist: grpcio-tools
|
17
|
-
Requires-Dist: grpc-interceptor<=0.15.
|
18
|
-
Requires-Dist: grpcio
|
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://
|
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
|
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">
|
@@ -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,
|
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
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: lamda
|
3
|
-
Version: 7.
|
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
|
16
|
-
Requires-Dist: grpcio-tools
|
17
|
-
Requires-Dist: grpc-interceptor<=0.15.
|
18
|
-
Requires-Dist: grpcio
|
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
|
@@ -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
|
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
|
23
|
-
"grpc-interceptor>=0.13.0,<=0.15.
|
24
|
-
"grpcio>=1.35.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
|
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
|