Initial commit
- Implemented Login
This commit is contained in:
commit
c0cf0bc40c
8 changed files with 185 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
__pycache__/
|
||||
.venv/
|
||||
*.egg-info/
|
||||
typings/
|
||||
persistent/
|
||||
14
Insthidge/__init__.py
Normal file
14
Insthidge/__init__.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
from slidge import entrypoint
|
||||
|
||||
from . import gateway, session
|
||||
|
||||
|
||||
def main():
|
||||
entrypoint("Insthidge")
|
||||
|
||||
|
||||
__all__ = (
|
||||
"gateway",
|
||||
"main",
|
||||
"session",
|
||||
)
|
||||
3
Insthidge/__main__.py
Normal file
3
Insthidge/__main__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from Insthidge import main
|
||||
|
||||
main()
|
||||
71
Insthidge/gateway.py
Normal file
71
Insthidge/gateway.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import asyncio
|
||||
|
||||
from instagrapi import Client
|
||||
from instagrapi.exceptions import (
|
||||
BadPassword,
|
||||
ChallengeRequired,
|
||||
FeedbackRequired,
|
||||
TwoFactorRequired,
|
||||
)
|
||||
from slidge import BaseGateway, GatewayUser
|
||||
from slidge.command.register import RegistrationType, TwoFactorNotRequired
|
||||
from slixmpp import JID
|
||||
|
||||
from .utils import get_session_file
|
||||
|
||||
|
||||
class Gateway(BaseGateway):
|
||||
COMPONENT_NAME = "Instagram (Slidge)"
|
||||
COMPONENT_TYPE = "instagram"
|
||||
COMPONENT_AVATAR = ("https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/"
|
||||
"Instagram_logo_2016.svg/640px-Instagram_logo_2016.svg.png")
|
||||
|
||||
ROSTER_GROUP = "instagram"
|
||||
|
||||
REGISTRATION_INSTRUCTIONS = "Enter instagram credentials"
|
||||
REGISTRATION_TYPE = RegistrationType.TWO_FACTOR_CODE
|
||||
|
||||
GROUPS = False
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.instagram_client = dict[str, Client]()
|
||||
|
||||
async def validate(self, user_jid: JID, registration_form: dict[str, str | None]):
|
||||
session_file = get_session_file(user_jid.bare)
|
||||
client = Client()
|
||||
try:
|
||||
_ = await asyncio.to_thread(client.login,
|
||||
registration_form["username"],
|
||||
registration_form["password"]
|
||||
)
|
||||
except TwoFactorRequired:
|
||||
self.instagram_client[user_jid.bare] = client
|
||||
except BadPassword as e:
|
||||
raise ValueError("Bad Password", e, e.args)
|
||||
except ChallengeRequired as e:
|
||||
raise ValueError("Browser Challenge Required", e, e.args)
|
||||
except FeedbackRequired as e:
|
||||
raise ValueError("Action moderated, account may be blocked", e, e.args)
|
||||
except Exception as e:
|
||||
raise ValueError("Could not authenticate: %s - %s", e, e.args)
|
||||
else:
|
||||
_ = await asyncio.to_thread(client.dump_settings, session_file)
|
||||
raise TwoFactorNotRequired
|
||||
|
||||
async def validate_two_factor_code(self, user: GatewayUser, code: str):
|
||||
session_file = get_session_file(user.jid.bare)
|
||||
client = self.instagram_client[user.jid.bare]
|
||||
try:
|
||||
if await asyncio.to_thread(client.login,
|
||||
user.legacy_module_data["username"],
|
||||
user.legacy_module_data["password"],
|
||||
verification_code=code):
|
||||
if not await asyncio.to_thread(client.dump_settings, session_file):
|
||||
raise IOError("Could not save session file: %s - %s", session_file)
|
||||
except ChallengeRequired as e:
|
||||
raise ValueError("Browser Challenge Required", e, e.args)
|
||||
except FeedbackRequired as e:
|
||||
raise ValueError("Action moderated, account may be blocked", e, e.args)
|
||||
except Exception as e:
|
||||
raise ValueError("Could not authenticate: %s - %s", e, e.args)
|
||||
25
Insthidge/session.py
Normal file
25
Insthidge/session.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import asyncio
|
||||
|
||||
import instagrapi
|
||||
from slidge import BaseSession
|
||||
|
||||
from .utils import get_session_file
|
||||
|
||||
|
||||
class Session(BaseSession):
|
||||
|
||||
def __init__(self, *a, **kw):
|
||||
super().__init__(*a, **kw)
|
||||
|
||||
async def login(self):
|
||||
client = instagrapi.Client()
|
||||
session_file = get_session_file(self.user_jid.bare)
|
||||
|
||||
client.load_settings(session_file)
|
||||
await asyncio.to_thread(client.login,
|
||||
self.user.legacy_module_data["username"],
|
||||
self.user.legacy_module_data["password"])
|
||||
|
||||
self.log.info(
|
||||
"Logged in: %s", str(self.user_jid.bare)
|
||||
)
|
||||
5
Insthidge/utils.py
Normal file
5
Insthidge/utils.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from slidge import global_config
|
||||
|
||||
|
||||
def get_session_file(user_bare_jid: str):
|
||||
return str(global_config.HOME_DIR / user_bare_jid)
|
||||
5
README.md
Normal file
5
README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Insthidge
|
||||
|
||||
A XMPP puppeteering gateway based on Slidge and Instagrapi
|
||||
|
||||
Chat with Instagram users wthout leaving XMPP.
|
||||
57
pyproject.toml
Normal file
57
pyproject.toml
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
[project]
|
||||
name = "Insthidge"
|
||||
description = "A XMPP puppeteering gateway based on Slidge and Instagrapi"
|
||||
authors = [
|
||||
{name = "Oliver Hattshire", email = "oliver@hattshire.dev"},
|
||||
]
|
||||
readme = "README.md"
|
||||
license = "Unlicense"
|
||||
classifiers = [
|
||||
"Topic :: Internet :: XMPP",
|
||||
]
|
||||
requires-python = ">= 3.11"
|
||||
keywords = ["xmpp", "chat", "instagram", "gateway", "bridge", "instant messaging"]
|
||||
version = "0.0.0a1"
|
||||
dependencies = [
|
||||
"slidge>=0.3,<0.4",
|
||||
"instagrapi>=2.2,<3",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
Insthidge = "Insthidge:main"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"mypy>=1.14.1",
|
||||
"ruff>=0.9.1",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools", "setuptools-scm"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["Insthidge"]
|
||||
|
||||
[tool.setuptools_scm]
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "pypi"
|
||||
url = "https://pypi.org/simple"
|
||||
|
||||
[tool.mypy]
|
||||
files = ["Insthidge"]
|
||||
check_untyped_defs = true
|
||||
strict = false
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = ["instagrapi.*"]
|
||||
ignore_missing_imports = true
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 88
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["I"]
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue