Browse Source

Catch consent_required error too

Tulir Asokan 3 years ago
parent
commit
ed98e82cff

+ 1 - 0
mauigpapi/errors/__init__.py

@@ -5,6 +5,7 @@ from .response import (
     IGBad2FACodeError,
     IGChallengeWrongCodeError,
     IGCheckpointError,
+    IGConsentRequiredError,
     IGFBNoContactPointFoundError,
     IGInactiveUserError,
     IGLoginBadPasswordError,

+ 13 - 1
mauigpapi/errors/response.py

@@ -19,7 +19,13 @@ from aiohttp import ClientResponse
 
 from mautrix.types import JSON, Serializable
 
-from ..types import CheckpointResponse, LoginErrorResponse, LoginRequiredResponse, SpamResponse
+from ..types import (
+    CheckpointResponse,
+    ConsentRequiredResponse,
+    LoginErrorResponse,
+    LoginRequiredResponse,
+    SpamResponse,
+)
 from .base import IGError
 
 
@@ -39,6 +45,8 @@ class IGResponseError(IGError):
         type_hint = get_type_hints(type(self)).get("body", JSON)
         if type_hint is not JSON and issubclass(type_hint, Serializable):
             self.body = type_hint.deserialize(json)
+        else:
+            self.body = json
         super().__init__(f"{prefix}: {self._message_override or message}")
 
     @property
@@ -70,6 +78,10 @@ class IGCheckpointError(IGResponseError):
         return self.body.challenge.api_path
 
 
+class IGConsentRequiredError(IGResponseError):
+    body: ConsentRequiredResponse
+
+
 class IGNotLoggedInError(IGResponseError):
     body: LoginRequiredResponse
 

+ 3 - 0
mauigpapi/http/base.py

@@ -31,6 +31,7 @@ from ..errors import (
     IGActionSpamError,
     IGBad2FACodeError,
     IGCheckpointError,
+    IGConsentRequiredError,
     IGFBNoContactPointFoundError,
     IGInactiveUserError,
     IGLoginBadPasswordError,
@@ -202,6 +203,8 @@ class BaseAndroidAPI:
                 err = IGCheckpointError(resp, data)
                 self.state.challenge_path = err.url
                 raise err
+            elif message == "consent_required":
+                raise IGConsentRequiredError(resp, data)
             elif message == "user_has_logged_out":
                 raise IGUserHasLoggedOutError(resp, data)
             elif message == "login_required":

+ 1 - 0
mauigpapi/types/__init__.py

@@ -14,6 +14,7 @@ from .direct_inbox import DMInbox, DMInboxCursor, DMInboxResponse, DMThreadRespo
 from .error import (
     CheckpointChallenge,
     CheckpointResponse,
+    ConsentRequiredResponse,
     LoginErrorResponse,
     LoginErrorResponseButton,
     LoginPhoneVerificationSettings,

+ 14 - 0
mauigpapi/types/error.py

@@ -52,6 +52,20 @@ class CheckpointResponse(SerializableAttrs):
     error_type: Optional[str] = None
 
 
+@dataclass
+class ConsentData(SerializableAttrs):
+    headline: str
+    content: str
+    button_text: str
+
+
+@dataclass
+class ConsentRequiredResponse(SerializableAttrs):
+    message: str  # consent_required
+    status: str  # fail
+    consent_data: ConsentData
+
+
 @dataclass
 class LoginRequiredResponse(SerializableAttrs):
     # TODO enum?

+ 16 - 7
mautrix_instagram/user.py

@@ -23,6 +23,7 @@ import time
 from mauigpapi import AndroidAPI, AndroidMQTT, AndroidState
 from mauigpapi.errors import (
     IGCheckpointError,
+    IGConsentRequiredError,
     IGNotLoggedInError,
     IGUserIDNotFoundError,
     IrisSubscribeError,
@@ -64,8 +65,9 @@ BridgeState.human_readable_errors.update(
     {
         "ig-connection-error": "Instagram disconnected unexpectedly",
         "ig-auth-error": "Authentication error from Instagram: {message}",
-        "ig-checkpoint": "Instagram checkpoint error. Please check Instagram website.",
-        "ig-checkpoint-locked": "Instagram checkpoint error. Please check Instagram website.",
+        "ig-checkpoint": "Instagram checkpoint error. Please check the Instagram website.",
+        "ig-consent-required": "Instagram requires a consent update. Please check the Instagram website.",
+        "ig-checkpoint-locked": "Instagram checkpoint error. Please check the Instagram website.",
         "ig-disconnected": None,
         "ig-no-mqtt": "You're not connected to Instagram",
         "logged-out": "You're not logged into Instagram",
@@ -179,7 +181,7 @@ class User(DBUser, BaseUser):
                 self.log.warning(f"Failed to connect to Instagram: {e}, logging out")
                 await self.logout(error=e)
                 return
-            except IGCheckpointError as e:
+            except (IGCheckpointError, IGConsentRequiredError) as e:
                 await self._handle_checkpoint(e, on="connect", client=client)
                 return
         self.client = client
@@ -352,10 +354,20 @@ class User(DBUser, BaseUser):
             self._is_refreshing = False
 
     async def _handle_checkpoint(
-        self, e: IGCheckpointError, on: str, client: AndroidAPI | None = None
+        self,
+        e: IGCheckpointError | IGConsentRequiredError,
+        on: str,
+        client: AndroidAPI | None = None,
     ) -> None:
         self.log.warning(f"Got checkpoint error on {on}: {e.body.serialize()}")
         client = client or self.client
+        self.client = None
+        self.mqtt = None
+        if isinstance(e, IGConsentRequiredError):
+            await self.push_bridge_state(
+                BridgeStateEvent.BAD_CREDENTIALS, error="ig-consent-required"
+            )
+            return
         error_code = "ig-checkpoint"
         try:
             resp = await client.challenge_reset()
@@ -364,9 +376,6 @@ class User(DBUser, BaseUser):
                 error_code = "ig-checkpoint-locked"
         except Exception:
             self.log.exception("Error resetting challenge state")
-        await self.push_bridge_state(BridgeStateEvent.BAD_CREDENTIALS, error=error_code)
-        self.client = None
-        self.mqtt = None
         # if on == "connect":
         #     await self.connect()
         # else: