Fix crash when logging in after a forced logout

Also tidy up bridge notices during the login flow
This commit is contained in:
Andrew Ferrazzutti 2021-06-08 00:24:00 -04:00
parent 3286d7e6e2
commit c5eea7b50b
5 changed files with 49 additions and 20 deletions

View File

@ -55,6 +55,11 @@ async def login_do(evt: CommandEvent, gen: AsyncGenerator[Tuple[str, str], None]
failure = False failure = False
async for item in gen: async for item in gen:
if item[0] == "qr": if item[0] == "qr":
message = "Open LINE on your primary device and scan this QR code:"
content = TextMessageEventContent(body=message, msgtype=MessageType.NOTICE)
content.set_reply(evt.event_id)
await evt.az.intent.send_message(evt.room_id, content)
url = item[1] url = item[1]
buffer = io.BytesIO() buffer = io.BytesIO()
image = qrcode.make(url) image = qrcode.make(url)
@ -69,7 +74,6 @@ async def login_do(evt: CommandEvent, gen: AsyncGenerator[Tuple[str, str], None]
content.set_edit(qr_event_id) content.set_edit(qr_event_id)
await evt.az.intent.send_message(evt.room_id, content) await evt.az.intent.send_message(evt.room_id, content)
else: else:
content.set_reply(evt.event_id)
qr_event_id = await evt.az.intent.send_message(evt.room_id, content) qr_event_id = await evt.az.intent.send_message(evt.room_id, content)
elif item[0] == "pin": elif item[0] == "pin":
pin = item[1] pin = item[1]
@ -79,9 +83,10 @@ async def login_do(evt: CommandEvent, gen: AsyncGenerator[Tuple[str, str], None]
content.set_edit(pin_event_id) content.set_edit(pin_event_id)
await evt.az.intent.send_message(evt.room_id, content) await evt.az.intent.send_message(evt.room_id, content)
else: else:
content.set_reply(evt.event_id)
pin_event_id = await evt.az.intent.send_message(evt.room_id, content) pin_event_id = await evt.az.intent.send_message(evt.room_id, content)
elif item[0] in ("failure", "error"): elif item[0] == "login_success":
await evt.reply("Successfully logged in, waiting for LINE to load...")
elif item[0] in ("login_failure", "error"):
# TODO Handle errors differently? # TODO Handle errors differently?
failure = True failure = True
reason = item[1] reason = item[1]
@ -91,7 +96,7 @@ async def login_do(evt: CommandEvent, gen: AsyncGenerator[Tuple[str, str], None]
# else: pass # else: pass
if not failure and evt.sender.command_status: if not failure and evt.sender.command_status:
await evt.reply("Successfully logged in") await evt.reply("LINE loading complete")
await evt.sender.sync() await evt.sender.sync()
# else command was cancelled or failed. Don't post message about it, "cancel" command or failure did already # else command was cancelled or failed. Don't post message about it, "cancel" command or failure did already
evt.sender.command_status = None evt.sender.command_status = None

View File

@ -119,8 +119,12 @@ class Client(RPCClient):
data.append(("pin", req["pin"])) data.append(("pin", req["pin"]))
event.set() event.set()
async def success_handler(req: LoginCommand) -> None:
data.append(("login_success", None))
event.set()
async def failure_handler(req: LoginCommand) -> None: async def failure_handler(req: LoginCommand) -> None:
data.append(("failure", req.get("reason"))) data.append(("login_failure", req.get("reason")))
event.set() event.set()
async def cancel_watcher() -> None: async def cancel_watcher() -> None:
@ -145,7 +149,8 @@ class Client(RPCClient):
self.add_event_handler("qr", qr_handler) self.add_event_handler("qr", qr_handler)
self.add_event_handler("pin", pin_handler) self.add_event_handler("pin", pin_handler)
self.add_event_handler("failure", failure_handler) self.add_event_handler("login_success", success_handler)
self.add_event_handler("login_failure", failure_handler)
try: try:
while True: while True:
await event.wait() await event.wait()
@ -158,4 +163,5 @@ class Client(RPCClient):
finally: finally:
self.remove_event_handler("qr", qr_handler) self.remove_event_handler("qr", qr_handler)
self.remove_event_handler("pin", pin_handler) self.remove_event_handler("pin", pin_handler)
self.remove_event_handler("failure", failure_handler) self.remove_event_handler("login_success", success_handler)
self.remove_event_handler("login_failure", failure_handler)

View File

@ -177,7 +177,7 @@ class User(DBUser, BaseUser):
await portal.handle_remote_receipt(receipt) await portal.handle_remote_receipt(receipt)
async def handle_logged_out(self) -> None: async def handle_logged_out(self) -> None:
await self.send_bridge_notice("Logged out of LINE. Please run the \"login\" command to log back in.") await self.send_bridge_notice("Logged out of LINE. Please run either \"login-qr\" or \"login-email\" to log back in.")
if self._connection_check_task: if self._connection_check_task:
self._connection_check_task.cancel() self._connection_check_task.cancel()
self._connection_check_task = None self._connection_check_task = None

View File

@ -135,11 +135,19 @@ export default class Client {
}) })
} }
sendFailure(reason) { sendLoginSuccess() {
this.log(`Sending failure to client${reason ? `: "${reason}"` : ""}`) this.log("Sending login success to client")
return this._write({ return this._write({
id: --this.notificationID, id: --this.notificationID,
command: "failure", command: "login_success",
})
}
sendLoginFailure(reason) {
this.log(`Sending login failure to client${reason ? `: "${reason}"` : ""}`)
return this._write({
id: --this.notificationID,
command: "login_failure",
reason, reason,
}) })
} }

View File

@ -207,7 +207,7 @@ export default class MessagesPuppeteer {
} }
const result = await Promise.race([ const result = await Promise.race([
() => this.page.waitForSelector("#wrap_message_sync", {timeout: 2000}) () => this.page.waitForSelector("#mainApp:not(.MdNonDisp)", {timeout: 2000})
.then(value => { .then(value => {
loginSuccess = true loginSuccess = true
return value return value
@ -227,11 +227,13 @@ export default class MessagesPuppeteer {
delete this.login_email delete this.login_email
delete this.login_password delete this.login_password
if (!loginSuccess) { const messageSyncElement = loginSuccess ? await this.page.waitForSelector("#wrap_message_sync") : null
if (!loginSuccess || !messageSyncElement) {
this._sendLoginFailure(result) this._sendLoginFailure(result)
return return
} }
this._sendLoginSuccess()
this.log("Waiting for sync") this.log("Waiting for sync")
try { try {
await this.page.waitForFunction( await this.page.waitForFunction(
@ -242,14 +244,12 @@ export default class MessagesPuppeteer {
// TODO Sometimes it gets stuck at 99%...?? // TODO Sometimes it gets stuck at 99%...??
}, },
{timeout: 10000}, // Assume 10 seconds is long enough {timeout: 10000}, // Assume 10 seconds is long enough
result) messageSyncElement)
} catch (err) { } catch (err) {
//this._sendLoginFailure(`Failed to sync: ${err}`) //this._sendLoginFailure(`Failed to sync: ${err}`)
this.log("LINE's sync took too long, assume it's fine and carry on...") this.log("LINE's sync took too long, assume it's fine and carry on...")
} finally { } finally {
const syncText = await this.page.evaluate( const syncText = await messageSyncElement.evaluate(e => e.innerText)
messageSyncElement => messageSyncElement.innerText,
result)
this.log(`Final sync text is: "${syncText}"`) this.log(`Final sync text is: "${syncText}"`)
} }
@ -758,14 +758,24 @@ export default class MessagesPuppeteer {
} }
} }
_sendLoginSuccess() {
this.error("Login success")
if (this.client) {
this.client.sendLoginSuccess().catch(err =>
this.error("Failed to send login success to client:", err))
} else {
this.log("No client connected, not sending login success")
}
}
_sendLoginFailure(reason) { _sendLoginFailure(reason) {
this.loginRunning = false this.loginRunning = false
this.error(`Login failure: ${reason ? reason : "cancelled"}`) this.error(`Login failure: ${reason ? reason : "cancelled"}`)
if (this.client) { if (this.client) {
this.client.sendFailure(reason).catch(err => this.client.sendLoginFailure(reason).catch(err =>
this.error("Failed to send failure reason to client:", err)) this.error("Failed to send login failure to client:", err))
} else { } else {
this.log("No client connected, not sending failure reason") this.log("No client connected, not sending login failure")
} }
} }