account.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. # mautrix-instagram - A Matrix-Instagram puppeting bridge.
  2. # Copyright (C) 2020 Tulir Asokan
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU Affero General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU Affero General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU Affero General Public License
  15. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. from typing import Optional, Type, TypeVar
  17. import json
  18. from ..types import CurrentUserResponse
  19. from .base import BaseAndroidAPI
  20. T = TypeVar('T')
  21. class AccountAPI(BaseAndroidAPI):
  22. async def current_user(self) -> CurrentUserResponse:
  23. return await self.std_http_get(f"/api/v1/accounts/current_user/", query={"edit": "true"},
  24. response_type=CurrentUserResponse)
  25. async def set_biography(self, text: str) -> CurrentUserResponse:
  26. # TODO entities?
  27. return await self.__command("set_biography", device_id=self.state.device.id, raw_text=text)
  28. async def set_profile_picture(self, upload_id: str) -> CurrentUserResponse:
  29. return await self.__command("change_profile_picture",
  30. use_fbuploader="true", upload_id=upload_id)
  31. async def remove_profile_picture(self) -> CurrentUserResponse:
  32. return await self.__command("remove_profile_picture")
  33. async def set_private(self, private: bool) -> CurrentUserResponse:
  34. return await self.__command("set_private" if private else "set_public")
  35. async def confirm_email(self, slug: str) -> CurrentUserResponse:
  36. # slug can contain slashes, but it shouldn't start or end with one
  37. return await self.__command(f"confirm_email/{slug}")
  38. async def send_recovery_flow_email(self, query: str):
  39. req = {
  40. "_csrftoken": self.state.cookies.csrf_token,
  41. "adid": "",
  42. "guid": self.state.device.uuid,
  43. "device_id": self.state.device.id,
  44. "query": query,
  45. }
  46. # TODO parse response content
  47. return await self.std_http_post(f"/api/v1/accounts/send_recovery_flow_email/", data=req)
  48. async def edit_profile(self, external_url: Optional[str] = None, gender: Optional[str] = None,
  49. phone_number: Optional[str] = None, username: Optional[str] = None,
  50. # TODO should there be a last_name?
  51. first_name: Optional[str] = None, biography: Optional[str] = None,
  52. email: Optional[str] = None) -> CurrentUserResponse:
  53. return await self.__command("edit_profile", device_id=self.state.device.id, email=email,
  54. external_url=external_url, first_name=first_name,
  55. username=username, phone_number=phone_number, gender=gender,
  56. biography=biography)
  57. async def __command(self, command: str, response_type: Type[T] = CurrentUserResponse,
  58. **kwargs: str) -> T:
  59. req = {
  60. "_csrftoken": self.state.cookies.csrf_token,
  61. "_uid": self.state.cookies.user_id,
  62. "_uuid": self.state.device.uuid,
  63. **kwargs,
  64. }
  65. return await self.std_http_post(f"/api/v1/accounts/{command}/", data=req,
  66. filter_nulls=True, response_type=response_type)
  67. async def read_msisdn_header(self, usage: str = "default"):
  68. req = {
  69. "mobile_subno_usage": usage,
  70. "device_id": self.state.device.uuid,
  71. }
  72. headers = {
  73. "X-DEVICE-ID": self.state.device.uuid,
  74. }
  75. return await self.std_http_post("/api/v1/accounts/read_msisdn_header/", data=req,
  76. headers=headers)
  77. async def msisdn_header_bootstrap(self, usage: str = "default"):
  78. req = {
  79. "mobile_subno_usage": usage,
  80. "device_id": self.state.device.uuid,
  81. }
  82. return await self.std_http_post("/api/v1/accounts/msisdn_header_bootstrap/", data=req)
  83. async def contact_point_prefill(self, usage: str = "default"):
  84. req = {
  85. "mobile_subno_usage": usage,
  86. "device_id": self.state.device.uuid,
  87. }
  88. return await self.std_http_post("/api/v1/accounts/contact_point_prefill/", data=req)
  89. async def get_prefill_candidates(self):
  90. req = {
  91. "android_device_id": self.state.device.id,
  92. "usages": json.dumps(["account_recovery_omnibox"]),
  93. "device_id": self.state.device.uuid,
  94. }
  95. # TODO parse response content
  96. return await self.std_http_post("/api/v1/accounts/get_prefill_candidates/", data=req)
  97. async def process_contact_point_signals(self):
  98. req = {
  99. "phone_id": self.state.device.phone_id,
  100. "_csrftoken": self.state.cookies.csrf_token,
  101. "_uid": self.state.cookies.user_id,
  102. "device_id": self.state.device.uuid,
  103. "_uuid": self.state.device.uuid,
  104. "google_tokens": json.dumps([]),
  105. }
  106. return await self.std_http_post("/api/v1/accounts/process_contact_point_signals/",
  107. data=req)