diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 90667e1..267a406 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,10 @@ +7.85 +* 支持 mDNS 广播服务 +* 支持枚举选择器选中的所有元素 +* 客户端添加自动重试机制 +* 修复 Bound 比较逻辑错误 +* 允许从远程加载证书 + 7.80 * 优化实时投屏流畅度 * 新增持久化 Hook 脚本支持 diff --git a/lamda/__init__.py b/lamda/__init__.py index fc3543b..d019103 100644 --- a/lamda/__init__.py +++ b/lamda/__init__.py @@ -2,4 +2,4 @@ # # Distributed under MIT license. # See file LICENSE for detail or copy at https://opensource.org/licenses/MIT -__version__ = "7.80" +__version__ = "7.85" diff --git a/lamda/client.py b/lamda/client.py index 3bbe9b5..03466be 100644 --- a/lamda/client.py +++ b/lamda/client.py @@ -57,6 +57,8 @@ sys.path.append(joinpath(dirname(__file__))) sys.path.append(joinpath(dirname(__file__), "rpc")) +# use native resolver to support mDNS +os.environ["GRPC_DNS_RESOLVER"] = "native" protos, services = grpc.protos_and_services("services.proto") __all__ = [ @@ -179,6 +181,8 @@ def contain(a, b): b.right <= a.right]) def equal(a, b): + if not isinstance(b, protos.Bound): + return False return all([b.top == a.top, b.left == a.left, b.bottom == a.bottom, @@ -194,6 +198,8 @@ def corner(b, position): Direction = protos.Direction GproxyType = protos.GproxyType GrantType = protos.GrantType +ScriptRuntime = protos.ScriptRuntime +DataEncode = protos.DataEncode Group = protos.Group Key = protos.Key @@ -256,8 +262,6 @@ def corner(b, position): TouchSequence.__getitem__ = touchSequenceIndexer TouchSequence.__iter__ = touchSequenceIter -DataEncode = protos.DataEncode -ScriptRuntime = protos.ScriptRuntime HookRpcRequest = protos.HookRpcRequest HookRpcResponse = protos.HookRpcResponse @@ -385,13 +389,14 @@ def raise_remote_exception(self, res): class ObjectUiAutomatorOpStub: - def __init__(self, stub, selector): + def __init__(self, caller, selector): """ UiAutomator 子接口,用来模拟出实例的意味 """ self._selector = selector self.selector = Selector(**selector) - self.stub = stub + self.stub = caller.stub + self.caller = caller def __str__(self): selector = ", ".join(["{}={}".format(k, v) \ for k, v in self._selector.items()]) @@ -494,6 +499,72 @@ def info_of_all_instances(self): req = protos.SelectorOnlyRequest(selector=self.selector) r = self.stub.selectorObjInfoOfAllInstances(req) return r.objects + def all_instances(self): + """ + 获取选择器选中的所有元素控件 + """ + return list(self) + def _new_object(self, **kwargs): + selector = copy.deepcopy(self._selector) + selector.update(**kwargs) + instance = self.caller(**selector) + return instance + def text(self, txt): + return self._new_object(text=txt) + def resourceId(self, name): + return self._new_object(resourceId=name) + def description(self, desc): + return self._new_object(description=desc) + def packageName(self, name): + return self._new_object(packageName=name) + def className(self, name): + return self._new_object(className=name) + def textContains(self, needle): + return self._new_object(textContains=needle) + def descriptionContains(self, needle): + return self._new_object(descriptionContains=needle) + def textStartsWith(self, needle): + return self._new_object(textStartsWith=needle) + def descriptionStartsWith(self, needle): + return self._new_object(descriptionStartsWith=needle) + def textMatches(self, match): + return self._new_object(textMatches=match) + def descriptionMatches(self, match): + return self._new_object(descriptionMatches=match) + def resourceIdMatches(self, match): + return self._new_object(resourceIdMatches=match) + def packageNameMatches(self, match): + return self._new_object(packageNameMatches=match) + def classNameMatches(self, match): + return self._new_object(classNameMatches=match) + def checkable(self, value): + return self._new_object(checkable=value) + def clickable(self, value): + return self._new_object(clickable=value) + def focusable(self, value): + return self._new_object(focusable=value) + def scrollable(self, value): + return self._new_object(scrollable=value) + def longClickable(self, value): + return self._new_object(longClickable=value) + def enabled(self, value): + return self._new_object(enabled=value) + def checked(self, value): + return self._new_object(checked=value) + def focused(self, value): + return self._new_object(focused=value) + def selected(self, value): + return self._new_object(selected=value) + def index(self, idx): + return self._new_object(index=idx) + def instance(self, idx): + return self._new_object(instance=idx) + def __iter__(self): + """ + 遍历所有符合选择器条件的元素实例 + """ + yield from [self.instance(i) for i in \ + range(self.count())] def count(self): """ 获取选择器选中控件的数量 @@ -962,7 +1033,7 @@ def wait_for_idle(self, timeout): r = self.stub.waitForIdle(protos.Integer(value=timeout)) return r.value def __call__(self, **kwargs): - return ObjectUiAutomatorOpStub(self.stub, kwargs) + return ObjectUiAutomatorOpStub(self, kwargs) class AppScriptRpcInterface(object): @@ -2042,6 +2113,14 @@ def __init__(self, host, port=65000, session=None): self.certificate = certificate self.server = "{0}:{1}".format(host, port) + policy = dict() + policy["maxAttempts"] = 5 + policy["retryableStatusCodes"] = ["UNAVAILABLE"] + policy["backoffMultiplier"] = 2 + policy["initialBackoff"] = "0.5s" + policy["maxBackoff"] = "15s" + config = json.dumps(dict(methodConfig=[{"name": [{}], + "retryPolicy": policy,}])) if certificate is not None: with open(certificate, "rb") as fd: key, crt, ca = self._parse_certdata(fd.read()) @@ -2051,10 +2130,14 @@ def __init__(self, host, port=65000, self._chan = grpc.secure_channel(self.server, creds, options=(("grpc.ssl_target_name_override", self._parse_cname(crt)), + ("grpc.service_config", config), ("grpc.enable_http_proxy", 0))) else: - self._chan = grpc.insecure_channel(self.server) + self._chan = grpc.insecure_channel(self.server, + options=(("grpc.service_config", config), + ("grpc.enable_http_proxy", 0)) + ) session = session or uuid.uuid4().hex interceptors = [ClientSessionMetadataInterceptor(session), GrpcRemoteExceptionInterceptor(), diff --git a/properties.local.example b/properties.local.example index dc56cd9..2957e04 100644 --- a/properties.local.example +++ b/properties.local.example @@ -1,125 +1,151 @@ -# properties.local 配置文件 +# properties.local configuration file # -# ------ 请勿直接复制此文件 请挑选所需配置新建文件 ------ -# -# 注意请务必确保该文件的属主以及权限为 root:root, 600 -# 此文件是 LAMDA 的默认配置文件,你可以在启动时让 LAMDA 自动启动一些服务 -# 文件应该位于 /data 或者 /data/usr (LAMDA 首次启动前不会存在该目录,如不存在请自行创建) -# 它的读取顺序为以上列出的顺序 -# -# 使用 # 开头的行为注释行,将被忽略 -# 请确保每行的格式均为 a=b 且不得包含空格 -# -# 如果文件中存在重复的配置项,最后一个重复的配置项将被使用,例如存在两行配置 -# openvpn.enable=false -# openvpn.enable=true -# 那么,最后一个 true 将被使用 +# DO NOT DIRECTLY COPY THIS FILE, PLEASE SELECT THE NECESSARY CONFIGURATION LINES TO CREATE A NEW FILE # +# This file is the LAMDA service configuration file. You can use +# it to automatically start some services when LAMDA starts. +# The file should be located in /data or /data/usr (this directory +# will not exist before the first startup, please create it if it does not exist). +# Lines starting with # and ; are comment lines and will be ignored. +# Please ensure that each line follows the format a=b and does not contain spaces. +# If there are duplicate configuration items across multiple files, +# the last duplicate will be used. -# 设置 LAMDA 的默认监听端口 +# Set the default listening port for LAMDA. port=65000 -# 你可以将远程桌面上显示的 LAMDA 改成任意你想要的名称(至多10字符) -brandname=LAMDA +# You can change the name displayed on the remote desktop for +# LAMDA to any name you prefer (up to 10 characters). +brandname=FIRERPA -# 设置 LAMDA 的远程桌面登录密码,6-32 位字符 -# 注意:此密码 仅在使用了证书 (--certificate) 的情况下才会生效 -# 因为如果不使用证书加密远程桌面以及API及其他流量,设置密码也为徒劳 -# 此密码用于作为证书中生成密码的备用密码(便于记忆) +# Set the LAMDA certificate. It will encrypt your remote desktop +# and API traffic, and enable password authentication. You can obtain +# the following configuration value by running 'base64 -w0 lamda.pem'. +# It is the base64-encoded certificate. +cert=TEFNREEgU1NMIENFUlRJRklDQVRFIChDTj10ZXN0LFBBU1NXRD1hMWMwZTNlYTcwN2E1NGRlN2EwZjk1KQotLS0tLUJFR0lOIFBSSVZBVEUgS0VZLS0tLS0KTUlJRXZnSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2d3Z2dTa0FnRUFBb0lCQVFEVmNMWlA5b0xRWkRIRgp5V0pTa2U0Z0crSUpmSCtMWlk0cXUzdS9OckRwSHZCN2k5V01rMWxRL2FMSGI0V3ZqelBLK1RITm9rRzc2MENRClhBTUpWS0dmYXRwcmNLUXdvMGhvWDZ2NlhsTVlZUlNRbW9wN3pSaUtnN3ZxKzV2S09DQ2RKcDFlSVNiZXcyTEgKTmYxL3JZelpwa1Q1bHoxTGZkem00eXJBS3VNa0tyZ3pnTzJRcE9CQVdYdmdiWG9BMDdidDdOODZZOGdNZFUwdAp6Ui9EcmhLTi9JMVdYSk11MU4wQW5UbDJRdEhEb0dCN0UyS0xpdmwybDZJdnRrYWJ4RE55Y2lHbUxOUGlMRklrCllPSHlnMUg3MUJ2NU04NE5TWDc1c2xuOXVNUGUzOVNFVlJoU0ptNHcvT2tXZnA5dGpZRUx3dHphdFhoSWJoS3MKaC9OZU1lOWRBZ01CQUFFQ2dnRUFCYlFuWUdlcFdKYjAydURtSnhLNGx2OFNhL0o1dzJpSldMYjk0dW1SUExRKwpTa1E5c1Zpc0JiQU1JNHc2dWFyNEFBVTh3WGxaTndPekMvM2V6dWNHRXFreEFReXM0VDB4SXRPUkF2WExxVlowCkl1WnpxNW53Si9OeFFzeEtmaWhBZkRLYlRmZjdmcG5MWlV0dlpNbG5LWUhQVExtRlFua3drckwyRE5YdDVVOTYKYXJUUDVOY0x1aDQ2dU93alJUOWhaNytYQi9ubU9LeTV4V3hoNWVMQmJJUTJrS0UvdWViUlVYRGZNdG5tbTh2aApRSG9VM3N5dzlZcE1xRDlWQWppcGlqQXRwbUlwa2w1emRWSE52Q1dCSGk2NjZxKzF6cUpHeFVUODBseHo1N2R1ClRvRFFQc1l0OFFEL3ZjNGkxajd0bDZyRzNQWkJNM05LNVR5ZFYyRnlnUUtCZ1FEYUcycnV3aWxyYUdZRzZNQWwKNEF2WW1BY0hHQWUwQjR0ZmtkdS9QandlRWQyWUF2TjJIQWV1Z1ZUSWg1eFplUlIwNFE4ZVNGenBTaEpwREpkNAp1TEhHcXJ2cmpXL1greEVIc081NnNjNjRiem1weWJWQXBlQnA4NlFGSTk4V3FmZkFyN3FzbzhweFJjNmdTRU1uCk5TcXV1Z2psYU05TlJmcUo4ci82RklmQkxRS0JnUUQ2aGJ0Z2dIdVJoTHhHYWNNaERvOVppcXJlNi9HN1dvZnQKR2FGZmFQM2xZNTNmM0hPdSsyNTZMWDY1ZWFYRTdrbXlQOGRDM2VWL24xT3dvTHdBYm1BZ2pEWVd1N09KdGk4QQpPbG9VNmtnTkVwNWcwOHpVWlBaR3NSMkZMd2VpUkgrQ3ZOdFBZakJydmFIQUtVU2lLa3BKdEpWeFpIdUl6SlpGCjVUZkM2VjNrOFFLQmdEeWp0TlpPKzA4V2hvOVROT0VTNnBnOHBHK1BlY3pPOEN3UkZJU1dYQWFNTnd6bGZTVVEKWS81YmpPUDMrRHRVRTZEdlZkRzRrc1IxeUtxV1NxTFF6dlNLVVpjTEN0YUV3bFplRmQvZEFibDdpdyt1dWdzUQpVMVdCM005bENzaDFWeUdtZWdNM3dyZzlqVlk0NFJyTWlHSnQ3TDFEcDZjM1ZwSDJBUFFac3lpOUFvR0JBTk9pCmpmeWtEYitNNXBDRllEWlkybmpHVURzcUQzZzZyb0Y2R1gxRWNOaU1JeDZ1V1h3RkkvdEsyN2RNTU9JQWUzbDkKcjVPcGFPczdhYlBZMVhsM3hQVTUvYWVPd2NrZ2d1d3FYMWN6NDlKSFhFeG9JSzE4N1NBakY5RWZQYyt6RmhVWAovaDA5MGJIeTdPWXM5cklZRDlIY0lETStzNjJKUjVtY1hsTG1Xay9CQW9HQkFKRVhQV05IWEwra1l6My91R1c3CnRKd0hUQzFlbEJjclcvaHpJMWt4ZEhXem5VaXNTWlcyVnA5b0wwSWNrQXVWQkx6eGUvR1h6OGJRTjZkOWwyZDAKdGtmUmo1TmpDOTUzS2N1cTNSekRmVU40cTcyUlVWTWlFOHVvSTBkVVZpalczN0tVMEhLcm1pbDBocU01eW9iNQpVZlhPQ2Q5SlRRSWx5Y2dNWER6Tm00S3oKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ3FEQ0NBWkNnQXdJQkFnSVJBUHNjMVBRNXBuSDNhNk1GZkdVTXA2WXdEUVlKS29aSWh2Y05BUUVMQlFBdwpFREVPTUF3R0ExVUVDZ3dGVEVGTlJFRXdIaGNOTWpBd01UQXhNREF3TURBeFdoY05Namt4TWpJNU1EQXdNREF4CldqQVBNUTB3Q3dZRFZRUUREQVIwWlhOME1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0MKQVFFQTFYQzJUL2FDMEdReHhjbGlVcEh1SUJ2aUNYeC9pMldPS3J0N3Z6YXc2Ujd3ZTR2VmpKTlpVUDJpeDIrRgpyNDh6eXZreHphSkJ1K3RBa0Z3RENWU2huMnJhYTNDa01LTklhRityK2w1VEdHRVVrSnFLZTgwWWlvTzc2dnViCnlqZ2duU2FkWGlFbTNzTml4elg5ZjYyTTJhWkUrWmM5UzMzYzV1TXF3Q3JqSkNxNE00RHRrS1RnUUZsNzRHMTYKQU5PMjdlemZPbVBJREhWTkxjMGZ3NjRTamZ5TlZseVRMdFRkQUowNWRrTFJ3NkJnZXhOaWk0cjVkcGVpTDdaRwptOFF6Y25JaHBpelQ0aXhTSkdEaDhvTlIrOVFiK1RQT0RVbCsrYkpaL2JqRDN0L1VoRlVZVWladU1QenBGbjZmCmJZMkJDOExjMnJWNFNHNFNySWZ6WGpIdlhRSURBUUFCTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBWEQ0L1cKQjBhSW1aWGpQbTRxUnBOazJmUnpjU1g4MGw2TlZaWWxJV3ZYalFxUXdXZnMvSGczZDVzYUpickFmcWVPa1lQdQpjeXJEWFZPdC9RTEVDOTFBSGtjRWJ1R0dPMGNFU2YyOHdUM1UzRnJJb2cxS1VyTURqWFFIb09vZEJpOGdNaVBmCmROcWhMSTdkNDJBTXJKU3dZUTlSUG9vWG9UZ2xDa0d3R291RDhuS0V5MmNHeVMxM3lQcDRseC9TWTR1QkRFU0sKRlErR0ZRTExGQktQZHZNc2x0cHYyQWFMWmR3clF4aFQ2aTU1U1puNStLb3c1TGxYL0RHdUw5UnRPdmZ2T0tzZQpRZ3pOQUg3QkYzbGdvQmJjYk9yZkVQazY1ZEZRN0NXYi91aDZjVmlmSjdxQzkvL0xhdElmb1VQVnJiRXdZL2dRCk5BRXFYclduMGZuYUc0cUEKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ2xEQ0NBWHdDQVFBd0RRWUpLb1pJaHZjTkFRRUxCUUF3RURFT01Bd0dBMVVFQ2d3RlRFRk5SRUV3SGhjTgpNakF3TVRBeE1EQXdNREF4V2hjTk1qa3hNakk1TURBd01EQXhXakFRTVE0d0RBWURWUVFLREFWTVFVMUVRVENDCkFTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTG5xZkJadnJHWmFxZ2s1bXNDUlJwUHoKcC8rNDY0akJrbmxtVEtldE9ja0RUVXE4VjZmSC8yR2ZiNkhqam9ENXBrQ3RENW1TS2thSE5odXhMWHNGZkVmYwpLbG1ubjNacGp5Tk9IRUEvaUFPMkR5RVlhMDh4U2V2TTdXb2piRjdjTmo1L0RZZzdlYjBpMCsvL2JCbGg4bmxPCmdoU1VoQ1RNNVBDb2ZMRFU4c1ZYdVlBaUdVNlV6QnJJQzB2SEVsdERraUpWTHBjQ3RzS2pFWk9za1BkQWM3dTYKL2FBMFA1R29uWjVVa1JEWXBhK2plSlVhYnFXWlFRRWd0bXZqbG1VVWlYd3UwalJuajFuMFQzZlBRRDNnQStMSQp2QUU5dmd2cFk1WFFqNm90cEJ2c1ozTUpKTktjVU1RdTF6T0FOVHpPMThUbEE4S29CTnNCeThaOURRWktYRjhDCkF3RUFBVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBZUduL055cUlSSS8wQUdxdkhQOTdLdFE3NlRqNmFjaGIKMzBMSVhXcCtZSFVhTWVBVmpkMlo3alNRcDVtWlpGbCtrMWZiMzM3SWVhR1hvZlZJMjFlSzUyUVgydGVOb0JrQQovVi9PMUh1MzUvK2FpejB4c2RENndXdndvNEZ5MWpsbWFlSmh3ZFFhY0JsREdGQTJqRkp4dUVwYWhmeFp2VXNiCjNqNXpVMFdLVFVDZkVEZ1hGd0J3MTJ4a3UvN1RNZENFYlJzWWFaM3pGVEMyMjZsUWJVRE43d2VxRndTRCt0QjYKUnVoSXhlOCtjRndBc0FXSENsZXJLZ1pucjN0NVFGMDc4cFcyR0h5OENzSjdWM01aVDVsWjQzbFM1TklCOUp6WgpTWXhaL2l6aFJ5aDVxUjczdUFnc0phTDU2QmorY1Fxbm9UcWhMWlZsN0orTTZXaFdLem9qc0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + +# Set the remote desktop login password for LAMDA, 6-32 characters. +# This password will only take effect if a certificate (--certificate) +# is used. It serves as a backup password to the one generated in +# the certificate (for easier memorization). ssl-web-credential=password123 -# 设置此项将同时导致 LAMDA 的 Python 客户端 API 停用 -# 此项在且仅在启动 LAMDA 后设备崩溃,或者你不需要使用 API 时设置 -# 此选项同时将禁用包括任何可能对系统稳定性产生影响的组件 +# Setting this option will also disable the LAMDA Python client API. +# This option should be set only if the device crashes after starting LAMDA, +# or if you do not need to use the API. This option will also disable +# any components that might impact system stability. disable-client-api=false -# 增强隐身模式,在可能损坏自身或第三方组件部分 -# 功能的情况下尽量保护 LAMDA 及其附属组件不被探测 -# 非必要请勿使用 (7.65 版本引入) +# Enhanced stealth mode, designed to protect LAMDA and its associated +# components from detection in cases where there is a risk of damaging +# itself or third-party components. +# Use only if necessary (introduced in version 7.65). enhanced-stealth-mode=false -# ---------- OpenVPN 配置 ---------- -# ***** 注意请勿手动编写此 OpenVPN 配置,你应该始终使用 tools -# ***** 目录下的 openvpn 镜像中提供的脚本来生成此配置 -# ***** 并做适当修改,以下是一个示例配置 +# Remote Desktop Touch Fix +# If there is an offset or no response when you touch the screen on +# the remote desktop, please set the following configuration: +touch.backend=system + +# ---------- OpenVPN Configuration ---------- +# Do not manually write the following configuration. You should use +# our accompanying OpenVPN server setup solution to set it up and +# generate this configuration using its built-in commands. openvpn.proto=udp openvpn.cipher=AES-256-GCM openvpn.host=123.123.123.123 openvpn.port=1190 -openvpn.ca=LS0tLS1CRUdJTiBDRVJUSUZJQ0FUR... -openvpn.cert=LS0tLS1CRUdJTiBDRVJUSUZJQ0FUR... -openvpn.key=LS0tLS1CRUdJTiBQUklWQVRFIEtFWS... -openvpn.tls_encryption=tls-crypt +openvpn.ca=LS0tLS1CRU... +openvpn.cert=LS0tLS1CRU... +openvpn.key=LS0tLS1CRU... +openvpn.tls_encryption= openvpn.tls_key_direction= -openvpn.tls_key=LS0tLS1CRUdJTiBP... -# ---- 以下为 OpenVPN 可配置项 ---- -# 是否开启全局 VPN +openvpn.tls_key= +# ONLY THE FOLLOWING CONFIGURATION ITEMS CAN BE MANUALLY CONFIGURED. +# Whether to enable global VPN. openvpn.global=false -# 是否启用 true | false +# Whether to enable the service true | false openvpn.enable=true -# ---------- Gproxy 配置 ---------- -# 此配置用来使 LAMDA 在启动时自动连接到代理 +# ---------- Proxy Configuration ---------- +# This configuration is used to make LAMDA automatically connect +# to the proxy server at startup. # -# 是否启用 true | false +# Whether to enable the service true | false gproxy.enable=true -# 代理类型 http-connect 或者 socks5 +# The proxy type can be either http-connect or socks5. gproxy.type=http-connect -# 代理服务器地址 +# Proxy server address gproxy.host=172.1.1.1 -# 代理服务器端口 +# Proxy server port gproxy.port=8080 -# 代理服务器的登录密码(置空则无认证) +# Proxy server login password (leave empty for no authentication) gproxy.password= -# 代理服务器的登录用户(置空则无认证) +# Proxy server login username (leave empty for no authentication) gproxy.login= -# ---------- CRONTAB 服务 ---------- -# 如果你不需要用到定时任务,可以关闭此服务 -# 是否启用 true | false +# ---------- CRONTAB Scheduled Task Service ---------- +# If you do not need scheduled tasks, you can disable this service. +# Whether to enable the service true | false cron.enable=true -# ---------- SSHD 服务 ---------- -# 如果你不需要用 ssh 连接设备,可以关闭此服务 -# 是否启用 true | false +# ---------- SSHD Service ---------- +# If you do not need to connect to the device via SSH, you can disable this service. +# Whether to enable the service true | false sshd.enable=true -# ---------- 端口转发(frp) 服务 ---------- -# 是否启用 true | false +# ---------- Port Forwarding (frp) Service ---------- +# Whether to enable the service true | false fwd.enable=true -# 转发到远端的端口(0则代表任意分配) +# Port to forward to the remote (0 means randomly allocated) fwd.rport=0 -# frp 服务器的地址 +# FRP server address fwd.host=123.123.123.123 -# frp 服务器端口 +# FRP server port fwd.port=9911 -# frp 协议 +# FRP protocol fwd.protocol=tcp -# frp 登录认证 +# FRP login authentication fwd.token=abc123 -# ---------- ADB 服务 ---------- -# 是否启用 true | false +# ---------- ADB Service ---------- +# Whether to enable the service true | false adb.enable=true -# 内置 adb 的默认目录 (adb shell 目录) +# Default working directory for built-in ADB (adb shell working directory) adb.directory=/data/local/tmp -# 如果为 true,那么 adb 连接将拥有 root 身份,否则为 shell 身份 -# 当此项配置为 false,你也将用于类原生的 adb shell,你将无法使用 LAMDA 内置命令 -# 同时请注意,由于 adb 并无 TLS 连接,流量可能会被监听,所以为了安全起见 -# 当 LAMDA 服务使用了certificate 启动时,默认情况下该值将自动设为 false -# 但当你将其写入 properties.local,则始终以文件中的配置为准 -# 请自行对安全性负责 +# If set to true, the ADB connection will have root privileges, +# otherwise it will have shell privileges. When this option is set to false, +# you will be using a native-like adb shell, and you will not be able to use +# LAMDA's built-in commands. Please note that since ADB does not use TLS connections, +# traffic may be monitored. For security reasons, when the LAMDA service is +# started with a certificate, this value will be set to false by default. +# However, if you specify it in the properties.local file, the configuration +# in the file will take precedence. +# You are responsible for ensuring security. adb.privileged=true -# ---------- 代理服务 ---------- -# 是否启用 true | false +# ---------- Bridge Proxy Service ---------- +# Whether to enable the service true | false tunnel2.enable=true -# 只有 login 以及 password 全部设置,代理才会需要登录验证,任一项留空代理将无需登录验证 +# The bridge proxy will require login authentication only if both login and password +# are set. If either one is left empty, no login authentication will be required. tunnel2.login=lamda -# 代理的登录密码 +# Login password for the bridge proxy tunnel2.password=1234 -# 出网接口 (rmnet|wlan) -# 当出网接口为 rmnet 时,代理将尝试通过移动数据转发你的请求 -# 当出网接口为 wlan 时,将通过 wlan 接口转发请求 -# 当配置为空时,将使用默认网络转发请求 -tunnel2.iface=rmnet \ No newline at end of file +# Outbound interface (rmnet|wlan) +# When the outbound interface is rmnet, the proxy will attempt to forward your requests through mobile data. +# When the outbound interface is wlan, requests will be forwarded through the wlan interface. +# If the configuration is empty, the default network will be used to forward the requests. +tunnel2.iface=rmnet + +# ---------- mDNS Broadcast Service ---------- +# Enable or disable true | false +mdns.enable=true +# Add TXT metadata for mDNS. When enabled, it will support querying device information +# such as model, ABI, and device ID using tools like python-zeroconf. Disabled by default. +mdns.meta=false +# Set the broadcast domain name using a locally unique ID, default is {DEVICEID-UNIQUE}.lamda. +# If the name duplicates in the local network, a suffix ID will be automatically added. +mdns.name=DEVICEID-UNIQUE.lamda +# Set the broadcast service name, default is lamda, i.e., _lamda._tcp.local. +mdns.service=lamda diff --git a/tools/startmitm.py b/tools/startmitm.py index e8c7622..af15958 100755 --- a/tools/startmitm.py +++ b/tools/startmitm.py @@ -172,7 +172,7 @@ def get_default_interface_ip(target): print (r" /____ > |__| (____ /__| |__| |__|_| /__||__| |__|_| / ") print (r" \/ \/ \/ \/ ") print (r" Android HTTP Traffic Capture ") -print (r"%60s" % ("lamda#v%s BY rev1si0n" % (__version__))) +print (r"%60s" % ("lamda#v%s BY firerpa" % (__version__))) pkgName = None