Prechádzať zdrojové kódy

Handle users who were previously logged out

Tulir Asokan 3 rokov pred
rodič
commit
7aa1bbcf41

+ 7 - 0
mauigpapi/errors/response.py

@@ -73,6 +73,13 @@ class IGCheckpointError(IGResponseError):
 class IGNotLoggedInError(IGResponseError):
     body: LoginRequiredResponse
 
+    @property
+    def proper_message(self) -> str:
+        return (
+            f"{self.body.error_title or self.body.message} "
+            f"(reason code: {self.body.logout_reason})"
+        )
+
 
 class IGUserHasLoggedOutError(IGNotLoggedInError):
     pass

+ 2 - 0
mauigpapi/types/error.py

@@ -58,6 +58,8 @@ class LoginRequiredResponse(SerializableAttrs):
     logout_reason: int
     message: str  # login_required or user_has_logged_out
     status: str  # fail
+    error_title: Optional[str] = None
+    error_body: Optional[str] = None
 
 
 @dataclass

+ 2 - 7
mautrix_instagram/commands/conn.py

@@ -46,14 +46,9 @@ async def ping(evt: CommandEvent) -> None:
     try:
         user_info = await evt.sender.client.current_user()
     except IGNotLoggedInError as e:
-        # TODO maybe don't always log out?
-        evt.log.exception(
-            f"Got error checking current user for %s, logging out. %s",
-            evt.sender.mxid,
-            e.body.json(),
-        )
+        evt.log.exception("Got error checking current user for %s", evt.sender.mxid)
         await evt.reply("You have been logged out")
-        await evt.sender.logout()
+        await evt.sender.logout(error=e)
     else:
         user = user_info.user
         await evt.reply(

+ 1 - 4
mautrix_instagram/db/user.py

@@ -72,9 +72,6 @@ class User:
 
     @classmethod
     async def all_logged_in(cls) -> list[User]:
-        q = (
-            "SELECT mxid, igpk, state, notice_room "
-            'FROM "user" WHERE igpk IS NOT NULL AND state IS NOT NULL'
-        )
+        q = 'SELECT mxid, igpk, state, notice_room FROM "user" WHERE igpk IS NOT NULL'
         rows = await cls.db.fetch(q)
         return [cls._from_row(row) for row in rows]

+ 18 - 11
mautrix_instagram/user.py

@@ -154,6 +154,9 @@ class User(DBUser, BaseUser):
         return bool(self.client) and bool(self.mqtt) and self._is_connected
 
     async def connect(self, user: CurrentUser | None = None) -> None:
+        if not self.state:
+            await self.push_bridge_state(BridgeStateEvent.BAD_CREDENTIALS, error="logged-out")
+            return
         client = AndroidAPI(self.state, log=self.api_log)
 
         if not user:
@@ -162,13 +165,7 @@ class User(DBUser, BaseUser):
                 user = resp.user
             except IGNotLoggedInError as e:
                 self.log.warning(f"Failed to connect to Instagram: {e}, logging out")
-                await self.send_bridge_notice(
-                    f"You have been logged out of Instagram: {e!s}",
-                    important=True,
-                    error_code="ig-auth-error",
-                    error_message=str(e),
-                )
-                await self.logout(from_error=True)
+                await self.logout(error=e)
                 return
         self.client = client
         self._is_logged_in = True
@@ -317,6 +314,9 @@ class User(DBUser, BaseUser):
                     try:
                         await self.sync()
                         return
+                    except IGNotLoggedInError as e:
+                        self.log.exception("Got not logged in error while syncing for refresh")
+                        await self.logout(error=e)
                     except Exception:
                         if retry_count >= 4:
                             raise
@@ -432,8 +432,8 @@ class User(DBUser, BaseUser):
         self._is_connected = False
         await self.update()
 
-    async def logout(self, from_error: bool = False) -> None:
-        if self.client:
+    async def logout(self, error: IGNotLoggedInError | None = None) -> None:
+        if self.client and error is None:
             try:
                 await self.client.logout(one_tap_app_login=False)
             except Exception:
@@ -442,7 +442,7 @@ class User(DBUser, BaseUser):
             self.mqtt.disconnect()
         self._track_metric(METRIC_CONNECTED, False)
         self._track_metric(METRIC_LOGGED_IN, False)
-        if not from_error:
+        if error is None:
             await self.push_bridge_state(BridgeStateEvent.LOGGED_OUT)
             puppet = await pu.Puppet.get_by_pk(self.igpk, create=False)
             if puppet and puppet.is_real_user:
@@ -453,7 +453,14 @@ class User(DBUser, BaseUser):
                 pass
             self.igpk = None
         else:
-            await self.push_bridge_state(BridgeStateEvent.BAD_CREDENTIALS)
+            self.log.debug("Auth error body: %s", error.body.serialize())
+            await self.send_bridge_notice(
+                f"You have been logged out of Instagram: {error.proper_message}",
+                important=True,
+                state_event=BridgeStateEvent.BAD_CREDENTIALS,
+                error_code="ig-auth-error",
+                error_message=error.proper_message,
+            )
         self.client = None
         self.mqtt = None
         self.state = None

+ 2 - 13
mautrix_instagram/web/provisioning_api.py

@@ -122,19 +122,8 @@ class ProvisioningAPI:
             try:
                 resp = await user.client.current_user()
             except IGNotLoggedInError as e:
-                # TODO maybe don't always log out?
-                self.log.exception(
-                    f"Got error checking current user for %s, logging out. %s",
-                    user.mxid,
-                    e.body.json(),
-                )
-                await user.send_bridge_notice(
-                    f"You have been logged out of Instagram: {e!s}",
-                    important=True,
-                    error_code="ig-auth-error",
-                    error_message=str(e),
-                )
-                await user.logout(from_error=True)
+                self.log.exception("Got error checking current user for %s", user.mxid)
+                await user.logout(error=e)
             else:
                 data["instagram"] = resp.user.serialize()
                 pl = user.state.device.payload