secure/pipeline/actions/signout.py
from secure.types import ActionResult, MSSession, PipelineContext
_DELETE_DEVICES_URL = "https://account.live.com/API/Proofs/DeleteDevices"
_UAID = "9b699236f4e94df58a700330b45a9b6b"
_SIGNOUT_BODY = {"uiflvr": 1001, "uaid": _UAID, "scid": 100109, "hpgid": 201030}
class SignoutAction:
name = "signout"
async def run(self, session: MSSession, ctx: PipelineContext) -> ActionResult:
headers = {
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest",
"canary": session.apicanary or "",
"hpgid": "201030",
"scid": "100109",
"uaid": _UAID,
"uiflvr": "1001",
"x-ms-apitransport": "xhr",
"x-ms-apiversion": "2",
}
try:
async with session.http.request(
"POST", _DELETE_DEVICES_URL, json=_SIGNOUT_BODY, headers=headers
) as resp:
try:
data = await resp.json()
except Exception:
data = {}
if resp.status >= 400:
ctx.log(f"signout: HTTP {resp.status}, body={str(data)[:300]}")
return ActionResult(self.name, False, detail=f"http_{resp.status}")
canary = (data.get("apiCanary") or data.get("canary")) if isinstance(data, dict) else None
if not canary:
return ActionResult(self.name, False, detail="no_canary_in_response")
return ActionResult(self.name, True, detail="signed_out")
except Exception as e:
ctx.log(f"signout: {type(e).__name__}: {e}")
return ActionResult(self.name, False, detail=f"{type(e).__name__}: {e}")