More changes

TODO: Rebase for cleaner changes
This commit is contained in:
Andrew Ferrazzutti 2021-02-10 02:34:19 -05:00
parent 26e8177f1c
commit d9487e6b12
43 changed files with 643 additions and 251 deletions

1
.gitignore vendored
View File

@ -11,6 +11,7 @@ __pycache__
/.eggs
profiles
puppet/extension_files
/config.yaml
/registration.yaml

View File

@ -31,19 +31,19 @@ RUN apk add --no-cache \
chmod +x yq && mv yq /usr/bin/yq
COPY requirements.txt /opt/mautrix-amp/requirements.txt
COPY optional-requirements.txt /opt/mautrix-amp/optional-requirements.txt
WORKDIR /opt/mautrix-amp
COPY requirements.txt /opt/mautrix-line/requirements.txt
COPY optional-requirements.txt /opt/mautrix-line/optional-requirements.txt
WORKDIR /opt/mautrix-line
RUN apk add --virtual .build-deps python3-dev libffi-dev build-base \
&& pip3 install -r requirements.txt -r optional-requirements.txt \
&& apk del .build-deps
COPY . /opt/mautrix-amp
COPY . /opt/mautrix-line
RUN apk add git && pip3 install .[e2be] && apk del git \
# This doesn't make the image smaller, but it's needed so that the `version` command works properly
&& cp mautrix_amp/example-config.yaml . && rm -rf mautrix_amp
&& cp mautrix_line/example-config.yaml . && rm -rf mautrix_line
VOLUME /data
ENV UID=1337 GID=1337
CMD ["/opt/mautrix-amp/docker-run.sh"]
CMD ["/opt/mautrix-line/docker-run.sh"]

View File

@ -2,10 +2,10 @@
# Define functions.
function fixperms {
chown -R $UID:$GID /data /opt/mautrix-amp
chown -R $UID:$GID /data /opt/mautrix-line
}
cd /opt/mautrix-amp
cd /opt/mautrix-line
if [ ! -f /data/config.yaml ]; then
cp example-config.yaml /data/config.yaml
@ -18,7 +18,7 @@ if [ ! -f /data/config.yaml ]; then
fi
if [ ! -f /data/registration.yaml ]; then
python3 -m mautrix_amp -g -c /data/config.yaml -r /data/registration.yaml
python3 -m mautrix_line -g -c /data/config.yaml -r /data/registration.yaml
echo "Didn't find a registration file."
echo "Generated one for you."
echo "Copy that over to synapses app service directory."
@ -27,4 +27,4 @@ if [ ! -f /data/registration.yaml ]; then
fi
fixperms
exec su-exec $UID:$GID python3 -m mautrix_amp -c /data/config.yaml
exec su-exec $UID:$GID python3 -m mautrix_line -c /data/config.yaml

View File

@ -1,55 +0,0 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import Optional
import io
import qrcode
import PIL as _
from mautrix.types import MediaMessageEventContent, MessageType, ImageInfo, EventID
from mautrix.bridge.commands import HelpSection, command_handler
from .typehint import CommandEvent
SECTION_AUTH = HelpSection("Authentication", 10, "")
@command_handler(needs_auth=False, management_only=True, help_section=SECTION_AUTH,
help_text="Log into Android Messages")
async def login(evt: CommandEvent) -> None:
status = await evt.sender.client.start()
if status.is_logged_in:
await evt.reply("You're already logged in")
return
qr_event_id: Optional[EventID] = None
async for url in evt.sender.client.login():
buffer = io.BytesIO()
image = qrcode.make(url)
size = image.pixel_size
image.save(buffer, "PNG")
qr = buffer.getvalue()
mxc = await evt.az.intent.upload_media(qr, "image/png", "login-qr.png", len(qr))
content = MediaMessageEventContent(body=url, url=mxc, msgtype=MessageType.IMAGE,
info=ImageInfo(mimetype="image/png", size=len(qr),
width=size, height=size))
if qr_event_id:
content.set_edit(qr_event_id)
await evt.az.intent.send_message(evt.room_id, content)
else:
content.set_reply(evt.event_id)
qr_event_id = await evt.az.intent.send_message(evt.room_id, content)
await evt.reply("Successfully logged in, now syncing")
await evt.sender.sync()

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -30,13 +30,13 @@ from . import commands as _
class MessagesBridge(Bridge):
module = "mautrix_amp"
name = "mautrix-amp"
command = "python -m mautrix-amp"
description = ("A very hacky Matrix-SMS bridge based on using "
"Android Messages for Web in Puppeteer.")
repo_url = "https://github.com/tulir/mautrix-amp"
real_user_content_key = "net.maunium.amp.puppet"
module = "mautrix_line"
name = "mautrix-line"
command = "python -m mautrix-line"
description = ("A very hacky Matrix-LINE bridge based on using"
"LINE's Chrome Store Extension in Puppeteer")
repo_url = "https://github.com/tulir/mautrix-line"
real_user_content_key = "net.maunium.line.puppet"
version = version
markdown_version = linkified_version
config_class = Config

View File

@ -0,0 +1,117 @@
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import Optional, AsyncGenerator, Tuple
import io
import qrcode
import PIL as _
from mautrix.types import TextMessageEventContent, MediaMessageEventContent, MessageType, ImageInfo, EventID
from mautrix.bridge.commands import HelpSection, command_handler
from .typehint import CommandEvent
SECTION_AUTH = HelpSection("Authentication", 10, "")
async def login_prep(evt: CommandEvent, login_type: str) -> bool:
status = await evt.sender.client.start()
if status.is_logged_in:
await evt.reply("You're already logged in")
return False
if evt.sender.command_status is not None:
action = evt.sender.command_status["action"]
if action == "Login":
await evt.reply(
"A login is already in progress. Please follow the login instructions, "
"or use the `$cmdprefix+sp cancel` command to start over.")
else:
await evt.reply(f"Cannot login while a {action} command is active.")
return False
evt.sender.command_status = {
"action": "Login",
"login_type": login_type,
}
return True
async def login_do(evt: CommandEvent, gen: AsyncGenerator[Tuple[str, str], None]) -> None:
qr_event_id: Optional[EventID] = None
pin_event_id: Optional[EventID] = None
failure = False
async for item in gen:
if item[0] == "qr":
url = item[1]
buffer = io.BytesIO()
image = qrcode.make(url)
size = image.pixel_size
image.save(buffer, "PNG")
qr = buffer.getvalue()
mxc = await evt.az.intent.upload_media(qr, "image/png", "login-qr.png", len(qr))
content = MediaMessageEventContent(body=url, url=mxc, msgtype=MessageType.IMAGE,
info=ImageInfo(mimetype="image/png", size=len(qr),
width=size, height=size))
if qr_event_id:
content.set_edit(qr_event_id)
await evt.az.intent.send_message(evt.room_id, content)
else:
content.set_reply(evt.event_id)
qr_event_id = await evt.az.intent.send_message(evt.room_id, content)
elif item[0] == "pin":
pin = item[1]
content = TextMessageEventContent(body=pin, msgtype=MessageType.NOTICE)
if pin_event_id:
content.set_edit(pin_event_id)
await evt.az.intent.send_message(evt.room_id, content)
else:
content.set_reply(evt.event_id)
pin_event_id = await evt.az.intent.send_message(evt.room_id, content)
elif item[0] in ("failure", "error"):
# TODO Handle errors differently?
reason = item[1]
failure = True
content = TextMessageEventContent(body=reason, msgtype=MessageType.NOTICE)
await evt.az.intent.send_message(evt.room_id, content)
# else: pass
if not failure and evt.sender.command_status:
await evt.reply("Successfully logged in, now syncing")
await evt.sender.sync()
# else command was cancelled or failed. Don't post message about it, "cancel" command or failure did already
evt.sender.command_status = None
@command_handler(needs_auth=False, management_only=True, help_section=SECTION_AUTH,
help_text="Log into LINE via QR code")
async def login_qr(evt: CommandEvent) -> None:
if not await login_prep(evt, "qr"):
return
gen = evt.sender.client.login(evt.sender)
await login_do(evt, gen)
@command_handler(needs_auth=False, management_only=True, help_section=SECTION_AUTH,
help_text="Log into LINE via email/password",
help_args="<_email_> <_password_>")
async def login_email(evt: CommandEvent) -> None:
if len(evt.args) != 2:
await evt.reply("Usage: `$cmdprefix+sp login <email> <password>`")
return
if not await login_prep(evt, "email"):
return
gen = evt.sender.client.login(
evt.sender,
login_data=dict(email=evt.args[0], password=evt.args[1]))
await login_do(evt, gen)

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -29,7 +29,7 @@ async def set_notice_room(evt: CommandEvent) -> None:
@command_handler(needs_auth=False, management_only=True, help_section=SECTION_CONNECTION,
help_text="Check if you're logged into Android Messages")
help_text="Check if you're logged into LINE")
async def ping(evt: CommandEvent) -> None:
status = await evt.sender.client.start()
if status.is_logged_in:

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -39,18 +39,18 @@ appservice:
shared_secret: generate
# The unique ID of this appservice.
id: amp
id: line
# Username of the appservice bot.
bot_username: ampbot
bot_username: linebot
# Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty
# to leave display name/avatar as-is.
bot_displayname: Android Messages bridge bot
bot_displayname: LINE bridge bot
bot_avatar: mxc://maunium.net/VuvevQiMRlOxuBVMBNEZZrxi
# Community ID for bridged users (changes registration file) and rooms.
# Must be created manually.
#
# Example: "+amp:example.com". Set to false to disable.
# Example: "+line:example.com". Set to false to disable.
community_id: false
# Authentication tokens for AS <-> HS communication. Autogenerated; do not modify.
@ -66,11 +66,11 @@ metrics:
bridge:
# Localpart template of MXIDs for remote users.
# {userid} is replaced with the user ID (phone or name converted into a mxid-friendly format).
username_template: "amp_{userid}"
username_template: "line_{userid}"
# Displayname template for remote users.
# {displayname} is replaced with the display name of the user.
# {phone} is replaced with the phone number or name of the user.
displayname_template: "{displayname} (SMS)"
displayname_template: "{displayname} (LINE)"
# Maximum length of displayname
displayname_max_length: 100
@ -129,7 +129,7 @@ bridge:
resend_bridge_info: false
# The prefix for commands. Only required in non-management rooms.
command_prefix: "!am"
command_prefix: "!line"
# This bridge only supports a single user
user: "@admin:example.com"
@ -139,7 +139,7 @@ puppeteer:
# Either unix or tcp
type: unix
# Only for type: unix
path: /var/run/mautrix-amp/puppet.sock
path: /var/run/mautrix-line/puppet.sock
# Only for type: tcp
host: localhost
port: 29395
@ -152,7 +152,7 @@ logging:
version: 1
formatters:
colored:
(): mautrix_amp.util.ColorFormatter
(): mautrix_line.util.ColorFormatter
format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s"
normal:
format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s"
@ -160,7 +160,7 @@ logging:
file:
class: logging.handlers.RotatingFileHandler
formatter: normal
filename: ./mautrix-amp.log
filename: ./mautrix-line.log
maxBytes: 10485760
backupCount: 10
console:

View File

@ -19,7 +19,7 @@ def run(cmd):
if os.path.exists(".git") and shutil.which("git"):
try:
git_revision = run(["git", "rev-parse", "HEAD"]).strip().decode("ascii")
git_revision_url = f"https://github.com/tulir/mautrix-amp/commit/{git_revision}"
git_revision_url = f"https://github.com/tulir/mautrix-line/commit/{git_revision}"
git_revision = git_revision[:8]
except (subprocess.SubprocessError, OSError):
git_revision = "unknown"

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -47,4 +47,4 @@ class MatrixHandler(BaseMatrixHandler):
inviter.notice_room = room_id
await inviter.update()
await self.az.intent.send_notice(room_id, "This room has been marked as your "
"Android Messages bridge notice room.")
"LINE bridge notice room.")

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -268,7 +268,7 @@ class Portal(DBPortal, BasePortal):
@property
def bridge_info_state_key(self) -> str:
return f"net.maunium.amp://androidmessages/{self.chat_id}"
return f"net.maunium.line://line/{self.chat_id}"
@property
def bridge_info(self) -> Dict[str, Any]:
@ -276,8 +276,8 @@ class Portal(DBPortal, BasePortal):
"bridgebot": self.az.bot_mxid,
"creator": self.main_intent.mxid,
"protocol": {
"id": "androidmessages",
"displayname": "Android Messages",
"id": "line",
"displayname": "LINE",
"avatar_url": self.config["appservice.bot_avatar"],
},
"channel": {

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -56,8 +56,9 @@ class Puppet(DBPuppet, BasePuppet):
cls.mxid_template = SimpleTemplate(cls.config["bridge.username_template"], "userid",
prefix="@", suffix=f":{cls.hs_domain}", type=str)
secret = cls.config["bridge.login_shared_secret"]
cls.login_shared_secret_map[cls.hs_domain] = secret.encode("utf-8") if secret else None
cls.login_device_name = "Android Messages Bridge"
if secret:
cls.login_shared_secret_map[cls.hs_domain] = secret.encode("utf-8")
cls.login_device_name = "LINE Bridge"
async def update_info(self, info: Participant) -> None:
update = False

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -13,20 +13,17 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import AsyncGenerator, TypedDict, List, Dict, Callable, Awaitable, Any
from typing import AsyncGenerator, TypedDict, List, Tuple, Dict, Callable, Awaitable, Any
from collections import deque
import asyncio
from .rpc import RPCClient
from .types import ChatListInfo, ChatInfo, Message, StartStatus
from mautrix_line.rpc.types import RPCError
class QRCommand(TypedDict):
url: str
class LoginComplete(Exception):
pass
class LoginCommand(TypedDict):
content: str
class Client(RPCClient):
@ -66,22 +63,48 @@ class Client(RPCClient):
self.add_event_handler("message", wrapper)
async def login(self) -> AsyncGenerator[str, None]:
# TODO Type hint for sender
async def login(self, sender, **login_data) -> AsyncGenerator[Tuple[str, str], None]:
login_data["login_type"] = sender.command_status["login_type"]
data = deque()
event = asyncio.Event()
async def qr_handler(req: QRCommand) -> None:
data.append(req["url"])
async def qr_handler(req: LoginCommand) -> None:
data.append(("qr", req["url"]))
event.set()
async def pin_handler(req: LoginCommand) -> None:
data.append(("pin", req["pin"]))
event.set()
async def failure_handler(req: LoginCommand) -> None:
data.append(("failure", req["reason"]))
event.set()
async def cancel_watcher() -> None:
try:
while sender.command_status is not None:
await asyncio.sleep(1)
await self._raw_request("cancel_login")
except asyncio.CancelledError:
pass
cancel_watcher_task = asyncio.create_task(cancel_watcher())
def login_handler(_fut: asyncio.Future) -> None:
cancel_watcher_task.cancel()
e = _fut.exception()
if e is not None:
data.append(("error", str(e)))
data.append(None)
event.set()
login_future = await self._raw_request("login")
login_future = await self._raw_request("login", **login_data)
login_future.add_done_callback(login_handler)
self.add_event_handler("qr", qr_handler)
self.add_event_handler("pin", pin_handler)
self.add_event_handler("failure", failure_handler)
try:
while True:
await event.wait()
@ -93,3 +116,5 @@ class Client(RPCClient):
event.clear()
finally:
self.remove_event_handler("qr", qr_handler)
self.remove_event_handler("pin", pin_handler)
self.remove_event_handler("failure", failure_handler)

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -30,7 +30,7 @@ from . import puppet as pu, portal as po
if TYPE_CHECKING:
from .__main__ import MessagesBridge
METRIC_CONNECTED = Gauge("bridge_connected", "Users connected to Android Messages")
METRIC_CONNECTED = Gauge("bridge_connected", "Users connected to LINE")
class User(DBUser, BaseUser):
@ -49,6 +49,7 @@ class User(DBUser, BaseUser):
def __init__(self, mxid: UserID, notice_room: Optional[RoomID] = None) -> None:
super().__init__(mxid=mxid, notice_room=notice_room)
self._notice_room_lock = asyncio.Lock()
self.command_status = None
self.is_whitelisted = self.is_admin = self.config["bridge.user"] == mxid
self.log = self.log.getChild(self.mxid)
self._metric_value = defaultdict(lambda: False)

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,5 +1,5 @@
# mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
# Copyright (C) 2020 Tulir Asokan
# mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
# Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -64,8 +64,8 @@ class ProvisioningAPI:
return None
for part in auth_parts:
part = part.strip()
if part.startswith("net.maunium.amp.auth-"):
return part[len("net.maunium.amp.auth-"):]
if part.startswith("net.maunium.line.auth-"):
return part[len("net.maunium.line.auth-"):]
return None
def check_token(self, request: web.Request) -> Awaitable['u.User']:
@ -94,7 +94,7 @@ class ProvisioningAPI:
user = await self.check_token(request)
data = {
"mxid": user.mxid,
"amp": {
"line": {
"connected": True,
} if await user.is_logged_in() else None,
}
@ -107,7 +107,7 @@ class ProvisioningAPI:
if status.is_logged_in:
raise web.HTTPConflict(text='{"error": "Already logged in"}', headers=self._headers)
ws = web.WebSocketResponse(protocols=["net.maunium.amp.login"])
ws = web.WebSocketResponse(protocols=["net.maunium.line.login"])
await ws.prepare(request)
try:
async for url in user.client.login():

View File

@ -7,11 +7,11 @@ RUN echo $'\
RUN apk add --no-cache chromium@edge
WORKDIR /opt/mautrix-amp/puppet
RUN chown node:node /opt/mautrix-amp/puppet
WORKDIR /opt/mautrix-line/puppet
RUN chown node:node /opt/mautrix-line/puppet
USER node
COPY package.json yarn.lock ./
RUN yarn --production && rm -rf node_modules/puppeteer/.local-chromium
COPY . /opt/mautrix-amp/puppet
COPY . /opt/mautrix-line/puppet
CMD ["yarn", "start", "--config", "/data/config.json", "--browser", "/usr/lib/chromium/chrome", "--no-sandbox"]

View File

@ -4,5 +4,6 @@
"path": "/var/run/mautrix-amp/puppet.sock"
},
"profile_dir": "./profiles",
"url": "chrome-extension://<extension-uuid>/index.html"
"url": "chrome-extension://<extension-uuid>/index.html",
"extension_dir": "./extension_files"
}

View File

@ -1,23 +1,23 @@
{
"name": "mautrix-amp-puppeteer",
"name": "mautrix-line-puppeteer",
"version": "0.1.0",
"description": "Puppeteer module for mautrix-amp",
"description": "Puppeteer module for mautrix-line",
"repository": {
"type": "git",
"url": "git+https://mau.dev/tulir/mautrix-amp.git"
"url": "git+https://mau.dev/tulir/mautrix-line.git"
},
"type": "module",
"main": "src/main.js",
"author": "Tulir Asokan <tulir@maunium.net>",
"license": "AGPL-3.0-or-later",
"homepage": "https://mau.dev/tulir/mautrix-amp",
"homepage": "https://mau.dev/tulir/mautrix-line",
"scripts": {
"start": "node ./src/main.js"
},
"dependencies": {
"arg": "^4.1.3",
"chrono-node": "^2.1.7",
"puppeteer": "5.1.0"
"puppeteer": "5.5.0"
},
"devDependencies": {
"babel-eslint": "^10.1.0",

View File

@ -1,5 +1,5 @@
// mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
// Copyright (C) 2020 Tulir Asokan
// mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
// Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by

View File

@ -1,5 +1,5 @@
// mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
// Copyright (C) 2020 Tulir Asokan
// mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
// Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
@ -116,6 +116,24 @@ export default class Client {
})
}
sendPIN(pin) {
this.log(`Sending PIN ${pin} to client`)
return this._write({
id: --this.notificationID,
command: "pin",
pin,
})
}
sendFailure(reason) {
this.log(`Sending failure "${reason}" to client`)
return this._write({
id: --this.notificationID,
command: "failure",
reason,
})
}
handleStart = async (req) => {
let started = false
if (this.puppet === null) {
@ -205,7 +223,8 @@ export default class Client {
start: this.handleStart,
stop: this.handleStop,
disconnect: () => this.stop(),
login: () => this.puppet.waitForLogin(),
login: req => this.puppet.waitForLogin(req.login_type, req.login_data),
cancel_login: () => this.puppet.cancelLogin(),
send: req => this.puppet.sendMessage(req.chat_id, req.text),
set_last_message_ids: req => this.puppet.setLastMessageIDs(req.msg_ids),
get_chats: () => this.puppet.getRecentChats(),

View File

@ -1,5 +1,5 @@
// mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
// Copyright (C) 2020 Tulir Asokan
// mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
// Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
@ -32,6 +32,20 @@ window.__mautrixReceiveChanges = function (changes) {}
* @return {Promise<void>}
*/
window.__mautrixReceiveQR = function (url) {}
/**
* @return {Promise<void>}
*/
window.__mautrixSendEmailCredentials = function () {}
/**
* @param {string} pin - The login PIN.
* @return {Promise<void>}
*/
window.__mautrixReceivePIN = function (pin) {}
/**
* @param {Element} button - The button to click when a QR code or PIN expires.
* @return {Promise<void>}
*/
window.__mautrixExpiry = function (button) {}
/**
* @param {number} id - The ID of the message that was sent
* @return {Promise<void>}
@ -41,7 +55,11 @@ window.__mautrixReceiveMessageID = function(id) {}
class MautrixController {
constructor() {
this.chatListObserver = null
this.qrCodeObserver = null
this.qrChangeObserver = null
this.qrAppearObserver = null
this.emailAppearObserver = null
this.pinAppearObserver = null
this.expiryObserver = null
}
/**
@ -312,6 +330,7 @@ class MautrixController {
if (this.chatListObserver !== null) {
this.removeChatListObserver()
}
/* TODO
this.chatListObserver = new MutationObserver(mutations => {
try {
this._observeChatListMutations(mutations)
@ -320,6 +339,7 @@ class MautrixController {
}
})
this.chatListObserver.observe(element, { childList: true, subtree: true })
*/
console.debug("Started chat list observer")
}
@ -334,27 +354,132 @@ class MautrixController {
}
}
addQRObserver(element) {
if (this.qrCodeObserver !== null) {
this.removeQRObserver()
addQRChangeObserver(element) {
if (this.qrChangeObserver !== null) {
this.removeQRChangeObserver()
}
this.qrCodeObserver = new MutationObserver(changes => {
this.qrChangeObserver = new MutationObserver(changes => {
for (const change of changes) {
if (change.attributeName === "data-qr-code" && change.target instanceof Element) {
window.__mautrixReceiveQR(change.target.getAttribute("data-qr-code"))
if (change.attributeName === "title" && change.target instanceof Element) {
window.__mautrixReceiveQR(change.target.getAttribute("title"))
}
}
})
this.qrCodeObserver.observe(element, {
this.qrChangeObserver.observe(element, {
attributes: true,
attributeFilter: ["data-qr-code"],
attributeFilter: ["title"],
})
}
removeQRObserver() {
if (this.qrCodeObserver !== null) {
this.qrCodeObserver.disconnect()
this.qrCodeObserver = null
removeQRChangeObserver() {
if (this.qrChangeObserver !== null) {
this.qrChangeObserver.disconnect()
this.qrChangeObserver = null
}
}
addQRAppearObserver(element) {
if (this.qrAppearObserver !== null) {
this.removeQRAppearObserver()
}
this.qrAppearObserver = new MutationObserver(changes => {
for (const change of changes) {
for (const node of change.addedNodes) {
const qrElement = node.querySelector("#login_qrcode_area div[title]")
if (qrElement) {
window.__mautrixReceiveQR(qrElement.title)
window.__mautrixController.addQRChangeObserver(element)
return
}
}
}
})
this.qrAppearObserver.observe(element, {
childList: true,
})
}
removeQRAppearObserver() {
if (this.qrAppearObserver !== null) {
this.qrAppearObserver.disconnect()
this.qrAppearObserver = null
}
}
addEmailAppearObserver(element, login_type) {
if (this.emailAppearObserver !== null) {
this.removeEmailAppearObserver()
}
this.emailAppearObserver = new MutationObserver(changes => {
for (const change of changes) {
for (const node of change.addedNodes) {
const emailElement = node.querySelector("#login_email_btn")
if (emailElement) {
window.__mautrixSendEmailCredentials()
return
}
}
}
})
this.emailAppearObserver.observe(element, {
childList: true,
})
}
removeEmailAppearObserver() {
if (this.emailAppearObserver !== null) {
this.emailAppearObserver.disconnect()
this.emailAppearObserver = null
}
}
addPINAppearObserver(element, login_type) {
if (this.pinAppearObserver !== null) {
this.removePINAppearObserver()
}
this.pinAppearObserver = new MutationObserver(changes => {
for (const change of changes) {
for (const node of change.addedNodes) {
const pinElement = node.querySelector("div.mdCMN01Code")
if (pinElement) {
window.__mautrixReceivePIN(pinElement.innerText)
return
}
}
}
})
this.pinAppearObserver.observe(element, {
childList: true,
})
}
removePINAppearObserver() {
if (this.pinAppearObserver !== null) {
this.pinAppearObserver.disconnect()
this.pinAppearObserver = null
}
}
addExpiryObserver(element) {
if (this.expiryObserver !== null) {
this.removeExpiryObserver()
}
const button = element.querySelector("dialog button")
this.expiryObserver = new MutationObserver(changes => {
if (changes.length == 1 && !changes[0].target.getAttribute("class").includes("MdNonDisp")) {
window.__mautrixExpiry(button)
}
})
this.expiryObserver.observe(element, {
attributes: true,
attributeFilter: ["class"],
})
}
removeExpiryObserver() {
if (this.expiryObserver !== null) {
this.expiryObserver.disconnect()
this.expiryObserver = null
}
}
}

View File

@ -1,5 +1,5 @@
// mautrix-amp - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
// Copyright (C) 2020 Tulir Asokan, Andrew Ferrazzutti
// mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
// Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
@ -38,6 +38,7 @@ const config = JSON.parse(fs.readFileSync(configPath).toString())
MessagesPuppeteer.profileDir = config.profile_dir || MessagesPuppeteer.profileDir
MessagesPuppeteer.disableDebug = !!config.disable_debug
MessagesPuppeteer.url = config.url
MessagesPuppeteer.extensionDir = config.extension_dir || MessagesPuppeteer.extensionDir
const api = new PuppetAPI(config.listen)

View File

@ -1,5 +1,5 @@
// mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
// Copyright (C) 2020 Tulir Asokan
// mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
// Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
@ -27,8 +27,9 @@ export default class MessagesPuppeteer {
static executablePath = undefined
static disableDebug = false
static noSandbox = false
static viewport = { width: 1920, height: 1080 }
//static viewport = { width: 1920, height: 1080 }
static url = undefined
static extensionDir = 'extension_files'
/**
*
@ -61,14 +62,13 @@ export default class MessagesPuppeteer {
* Start the browser and open the messages for web page.
* This must be called before doing anything else.
*/
async start(debug = false) {
async start() {
this.log("Launching browser")
const pathToExtension = require('path').join(__dirname, 'extension_files');
const extensionArgs = [
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`
];
const extensionArgs = [
`--disable-extensions-except=${MessagesPuppeteer.extensionDir}`,
`--load-extension=${MessagesPuppeteer.extensionDir}`
]
this.browser = await puppeteer.launch({
executablePath: MessagesPuppeteer.executablePath,
@ -85,67 +85,182 @@ export default class MessagesPuppeteer {
this.page = await this.browser.newPage()
}
this.log("Opening", MessagesPuppeteer.url)
await this.page.goto(MessagesPuppeteer.url)
await this.page.setBypassCSP(true) // Needed to load content scripts
await this._preparePage(true)
this.log("Injecting content script")
await this.page.addScriptTag({ path: "./src/contentscript.js", type: "module" })
this.log("Exposing functions")
await this.page.exposeFunction("__mautrixReceiveQR", this._receiveQRChange.bind(this))
await this.page.exposeFunction("__mautrixSendEmailCredentials", this._sendEmailCredentials.bind(this))
await this.page.exposeFunction("__mautrixReceivePIN", this._receivePIN.bind(this))
await this.page.exposeFunction("__mautrixExpiry", this._receiveExpiry.bind(this))
/* TODO
await this.page.exposeFunction("__mautrixReceiveMessageID",
id => this.sentMessageIDs.add(id))
await this.page.exposeFunction("__mautrixReceiveChanges",
this._receiveChatListChanges.bind(this))
await this.page.exposeFunction("__chronoParseDate", chrono.parseDate)
*/
this.log("Waiting for load")
// Wait for the page to load (either QR code for login or chat list when already logged in)
await Promise.race([
this.page.waitForSelector("mw-main-container mws-conversations-list .conv-container",
{ visible: true, timeout: 60000 }),
this.page.waitForSelector("mw-authentication-container mw-qr-code",
{ visible: true, timeout: 60000 }),
this.page.waitForSelector("mw-unable-to-connect-container",
{ visible: true, timeout: 60000 }),
])
// NOTE Must *always* re-login on a browser session, so no need to check if already logged in
this.loginRunning = false
this.loginCancelled = false
this.taskQueue.start()
if (await this.isLoggedIn()) {
await this.startObserving()
}
this.log("Startup complete")
}
async _preparePage(navigateTo) {
if (navigateTo) {
await this.page.goto(MessagesPuppeteer.url)
} else {
await this.page.reload()
}
this.log("Injecting content script")
await this.page.addScriptTag({ path: "./src/contentscript.js", type: "module" })
}
/**
* Wait for the session to be logged in and monitor QR code changes while it's not.
* Wait for the session to be logged in and monitor changes while it's not.
*/
async waitForLogin() {
async waitForLogin(login_type, login_data) {
if (await this.isLoggedIn()) {
return
}
const qrSelector = "mw-authentication-container mw-qr-code"
if (!await this.page.$("mat-slide-toggle.mat-checked")) {
this.log("Clicking Remember Me button")
await this.page.click("mat-slide-toggle:not(.mat-checked) > label")
} else {
this.log("Remember Me button already clicked")
this.loginRunning = true
this.loginCancelled = false
const loginContentArea = await this.page.waitForSelector("#login_content")
switch (login_type) {
case "qr": {
this.log("Running QR login")
const qrButton = await this.page.waitForSelector("#login_qr_btn")
await qrButton.click()
const qrElement = await this.page.waitForSelector("#login_qrcode_area div[title]", {visible: true})
const currentQR = await this.page.evaluate(element => element.title, qrElement)
this._receiveQRChange(currentQR)
await this.page.evaluate(
element => window.__mautrixController.addQRChangeObserver(element), qrElement)
await this.page.evaluate(
element => window.__mautrixController.addQRAppearObserver(element), loginContentArea)
break
}
this.log("Fetching current QR code")
const currentQR = await this.page.$eval(qrSelector,
element => element.getAttribute("data-qr-code"))
this._receiveQRChange(currentQR)
this.log("Adding QR observer")
await this.page.$eval(qrSelector,
element => window.__mautrixController.addQRObserver(element))
this.log("Waiting for login")
await this.page.waitForSelector("mws-conversations-list .conv-container", {
visible: true,
timeout: 0,
})
this.log("Removing QR observer")
await this.page.evaluate(() => window.__mautrixController.removeQRObserver())
case "email": {
this.log("Running email login")
if (!login_data) {
_sendLoginFailure("No login credentials provided for email login")
return
}
const emailButton = await this.page.waitForSelector("#login_email_btn")
await emailButton.click()
const emailArea = await this.page.waitForSelector("#login_email_area", {visible: true})
this.login_email = login_data["email"]
this.login_password = login_data["password"]
this._sendEmailCredentials()
await this.page.evaluate(
element => window.__mautrixController.addEmailAppearObserver(element), loginContentArea)
break
}
// TODO Phone number login
default:
_sendLoginFailure(`Invalid login type: ${login_type}`)
return
}
await this.page.evaluate(
element => window.__mautrixController.addPINAppearObserver(element), loginContentArea)
await this.page.$eval("#layer_contents",
element => window.__mautrixController.addExpiryObserver(element))
this.log("Waiting for login response")
let doneWaiting = false
let loginSuccess = false
const cancelableResolve = (promiseWithShortTimeout) => {
const executor = (resolve, reject) => {
promiseWithShortTimeout.then(
value => {
this.log(`Done: ${value}`)
doneWaiting = true
resolve(value)
},
reason => {
if (!doneWaiting) {
this.log(`Not done, waiting some more. ${reason}`)
setTimeout(executor, 3000, resolve, reject)
} else {
this.log(`Final fail. ${reason}`)
resolve()
}
}
)
}
return new Promise(executor)
}
const result = await Promise.race([
this.page.waitForSelector("#wrap_message_sync", {timeout: 2000})
.then(element => {
loginSuccess = true
return element
}),
this.page.waitForSelector("#login_incorrect", {visible: true, timeout: 2000})
.then(element => element.innerText),
this._waitForLoginCancel(),
].map(promise => cancelableResolve(promise)))
this.log("Removing observers")
await this.page.evaluate(() => window.__mautrixController.removeQRChangeObserver())
await this.page.evaluate(() => window.__mautrixController.removeLoginChildrenObserver(element))
await this.page.evaluate(() => window.__mautrixController.removeExpiryObserver())
delete this.login_email
delete this.login_password
if (!loginSuccess) {
_sendLoginFailure(result)
return
}
this.log("Waiting for sync")
await this.page.waitForFunction(
messageSyncElement => {
const text = messageSyncElement.innerText
return text == 'Syncing messages... 100%'
},
{},
result)
await this.startObserving()
this.loginRunning = false
this.log("Login complete")
}
/**
* Cancel an ongoing login attempt.
*/
async cancelLogin() {
if (this.loginRunning) {
this.loginCancelled = true
//await this._preparePage(false)
}
}
_waitForLoginCancel() {
return new Promise((resolve, reject) => {
console.log(`>>>>> ${this.loginCancelled}`)
if (this.loginCancelled) {
resolve()
} else {
reject()
}
})
}
/**
* Close the browser.
*/
@ -166,14 +281,17 @@ export default class MessagesPuppeteer {
* @return {Promise<boolean>} - Whether or not the session is logged in.
*/
async isLoggedIn() {
return await this.page.$("mw-main-container mws-conversations-list") !== null
return await this.page.$("#wrap_message_sync") !== null
}
async isPermanentlyDisconnected() {
return await this.page.$("mw-unable-to-connect-container") !== null
// TODO
//return await this.page.$("mw-unable-to-connect-container") !== null
return false
}
async isOpenSomewhereElse() {
/* TODO
try {
const text = await this.page.$eval("mws-dialog mat-dialog-content div",
elem => elem.textContent)
@ -181,16 +299,15 @@ export default class MessagesPuppeteer {
} catch (err) {
return false
}
}
async clickDialogButton() {
await this.page.click("mws-dialog mat-dialog-actions button")
*/
return false
}
async isDisconnected() {
if (!await this.isLoggedIn()) {
return true
}
/* TODO
const offlineIndicators = await Promise.all([
this.page.$("mw-main-nav mw-banner mw-error-banner"),
this.page.$("mw-main-nav mw-banner mw-information-banner[title='Connecting']"),
@ -198,6 +315,8 @@ export default class MessagesPuppeteer {
this.isOpenSomewhereElse(),
])
return offlineIndicators.some(indicator => Boolean(indicator))
*/
return false
}
/**
@ -206,8 +325,11 @@ export default class MessagesPuppeteer {
* @return {Promise<[ChatListInfo]>} - List of chat IDs in order of most recent message.
*/
async getRecentChats() {
/* TODO
return await this.page.$eval("mws-conversations-list .conv-container",
elem => window.__mautrixController.parseChatList(elem))
*/
return null
}
/**
@ -266,7 +388,7 @@ export default class MessagesPuppeteer {
async startObserving() {
this.log("Adding chat list observer")
await this.page.$eval("mws-conversations-list .conv-container",
await this.page.$eval("#wrap_chat_list",
element => window.__mautrixController.addChatListObserver(element))
}
@ -276,7 +398,9 @@ export default class MessagesPuppeteer {
}
_listItemSelector(id) {
return `mws-conversation-list-item > a.list-item[href="/web/conversations/${id}"]`
// TODO
//return `mws-conversation-list-item > a.list-item[href="/web/conversations/${id}"]`
return ''
}
async _switchChatUnsafe(id) {
@ -365,6 +489,20 @@ export default class MessagesPuppeteer {
}
}
async _sendEmailCredentials() {
this.log("Inputting login credentials")
// Triple-click email input field to select all existing text and replace it on type
const emailInput = await this.page.$("#line_login_email")
await emailInput.click({clickCount: 3})
await emailInput.type(this.login_email)
// Password input field always starts empty, so no need to select its text first
await this.page.type("#line_login_pwd", this.login_password)
await this.page.click("button#login_btn")
}
_receiveQRChange(url) {
if (this.client) {
this.client.sendQRCode(url).catch(err =>
@ -373,4 +511,28 @@ export default class MessagesPuppeteer {
this.log("No client connected, not sending new QR")
}
}
_receivePIN(pin) {
if (this.client) {
this.client.sendPIN(`Your PIN is: ${pin}`).catch(err =>
this.error("Failed to send new PIN to client:", err))
} else {
this.log("No client connected, not sending new PIN")
}
}
_sendLoginFailure(reason) {
this.error(`Login failure: ${reason ? reason : 'cancelled'}`)
if (this.client) {
this.client.sendFailure(reason).catch(err =>
this.error("Failed to send failure reason to client:", err))
} else {
this.log("No client connected, not sending failure reason")
}
}
async _receiveExpiry(button) {
this.log("Something expired, clicking OK button to continue")
await this.page.click(button)
}
}

View File

@ -1,5 +1,5 @@
// mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
// Copyright (C) 2020 Tulir Asokan
// mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
// Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by

View File

@ -1,5 +1,5 @@
// mautrix-amp - A very hacky Matrix-SMS bridge based on using Android Messages for Web in Puppeteer
// Copyright (C) 2020 Tulir Asokan
// mautrix-line - A very hacky Matrix-LINE bridge based on using LINE's Chrome Store Extension in Puppeteer
// Copyright (C) 2021 Tulir Asokan, Andrew Ferrazzutti
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by

View File

@ -364,10 +364,10 @@ define-properties@^1.1.2, define-properties@^1.1.3:
dependencies:
object-keys "^1.0.12"
devtools-protocol@0.0.767361:
version "0.0.767361"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.767361.tgz#5977f2558b84f9df36f62501bdddb82f3ae7b66b"
integrity sha512-ziRTdhEVQ9jEwedaUaXZ7kl9w9TF/7A3SXQ0XuqrJB+hMS62POHZUWTbumDN2ehRTfvWqTPc2Jw4gUl/jggmHA==
devtools-protocol@0.0.818844:
version "0.0.818844"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.818844.tgz#d1947278ec85b53e4c8ca598f607a28fa785ba9e"
integrity sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg==
doctrine@1.5.0:
version "1.5.0"
@ -918,11 +918,6 @@ lodash@^4.17.14, lodash@^4.17.19:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
mime@^2.0.3:
version "2.4.6"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1"
integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@ -935,11 +930,6 @@ minimist@^1.2.0, minimist@^1.2.5:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
mitt@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230"
integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
mkdirp-classic@^0.5.2:
version "0.5.3"
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
@ -967,6 +957,11 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
node-fetch@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
normalize-package-data@^2.3.2:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@ -1162,17 +1157,16 @@ punycode@^2.1.0:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
puppeteer@5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.1.0.tgz#e7bae2caa6e3a13a622755e4c27689d9812c38ca"
integrity sha512-IZBFG8XcA+oHxYo5rEpJI/HQignUis2XPijPoFpNxla2O+WufonGsUsSqrhRXgBKOME5zNfhRdUY2LvxAiKlhw==
puppeteer@5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.5.0.tgz#331a7edd212ca06b4a556156435f58cbae08af00"
integrity sha512-OM8ZvTXAhfgFA7wBIIGlPQzvyEETzDjeRa4mZRCRHxYL+GNH5WAuYUQdja3rpWZvkX/JKqmuVgbsxDNsDFjMEg==
dependencies:
debug "^4.1.0"
devtools-protocol "0.0.767361"
devtools-protocol "0.0.818844"
extract-zip "^2.0.0"
https-proxy-agent "^4.0.0"
mime "^2.0.3"
mitt "^2.0.1"
node-fetch "^2.6.1"
pkg-dir "^4.2.0"
progress "^2.0.1"
proxy-from-env "^1.0.0"