Increase security and reformat
This commit is contained in:
@@ -12,8 +12,7 @@ class ClientBase(ABC):
|
||||
self.log.info(f"{self.service.capitalize()} client initialising...")
|
||||
|
||||
@abstractmethod
|
||||
def start(self):
|
||||
...
|
||||
def start(self): ...
|
||||
|
||||
# @abstractmethod
|
||||
# async def send_message(self, recipient, message):
|
||||
|
||||
@@ -12,7 +12,15 @@ from django.urls import reverse
|
||||
from signalbot import Command, Context, SignalBot
|
||||
|
||||
from core.clients import ClientBase, signalapi, transport
|
||||
from core.messaging import ai, history, media_bridge, natural, replies, reply_sync, utils
|
||||
from core.messaging import (
|
||||
ai,
|
||||
history,
|
||||
media_bridge,
|
||||
natural,
|
||||
replies,
|
||||
reply_sync,
|
||||
utils,
|
||||
)
|
||||
from core.models import (
|
||||
Chat,
|
||||
Manipulation,
|
||||
@@ -402,7 +410,9 @@ class NewSignalBot(SignalBot):
|
||||
seen_user_ids.add(pi.user_id)
|
||||
users.append(pi.user)
|
||||
if not users:
|
||||
self.log.debug("[Signal] _upsert_groups: no PersonIdentifiers found — skipping")
|
||||
self.log.debug(
|
||||
"[Signal] _upsert_groups: no PersonIdentifiers found — skipping"
|
||||
)
|
||||
return
|
||||
|
||||
for user in users:
|
||||
@@ -423,7 +433,9 @@ class NewSignalBot(SignalBot):
|
||||
},
|
||||
)
|
||||
|
||||
self.log.info("[Signal] upserted %d groups for %d users", len(groups), len(users))
|
||||
self.log.info(
|
||||
"[Signal] upserted %d groups for %d users", len(groups), len(users)
|
||||
)
|
||||
|
||||
async def _detect_groups(self):
|
||||
await super()._detect_groups()
|
||||
@@ -505,7 +517,9 @@ class HandleMessage(Command):
|
||||
source_uuid_norm and dest_norm and source_uuid_norm == dest_norm
|
||||
)
|
||||
|
||||
is_from_bot = bool(bot_uuid and source_uuid_norm and source_uuid_norm == bot_uuid)
|
||||
is_from_bot = bool(
|
||||
bot_uuid and source_uuid_norm and source_uuid_norm == bot_uuid
|
||||
)
|
||||
if (not is_from_bot) and bot_phone_digits and source_phone_digits:
|
||||
is_from_bot = source_phone_digits == bot_phone_digits
|
||||
# Inbound deliveries usually do not have destination fields populated.
|
||||
@@ -596,9 +610,9 @@ class HandleMessage(Command):
|
||||
candidate_digits = {value for value in candidate_digits if value}
|
||||
if candidate_digits:
|
||||
signal_rows = await sync_to_async(list)(
|
||||
PersonIdentifier.objects.filter(service=self.service).select_related(
|
||||
"user"
|
||||
)
|
||||
PersonIdentifier.objects.filter(
|
||||
service=self.service
|
||||
).select_related("user")
|
||||
)
|
||||
matched = []
|
||||
for row in signal_rows:
|
||||
@@ -718,13 +732,13 @@ class HandleMessage(Command):
|
||||
target_ts=int(reaction_payload.get("target_ts") or 0),
|
||||
emoji=str(reaction_payload.get("emoji") or ""),
|
||||
source_service="signal",
|
||||
actor=(
|
||||
effective_source_uuid or effective_source_number or ""
|
||||
),
|
||||
actor=(effective_source_uuid or effective_source_number or ""),
|
||||
target_author=str(
|
||||
(reaction_payload.get("raw") or {}).get("targetAuthorUuid")
|
||||
or (reaction_payload.get("raw") or {}).get("targetAuthor")
|
||||
or (reaction_payload.get("raw") or {}).get("targetAuthorNumber")
|
||||
or (reaction_payload.get("raw") or {}).get(
|
||||
"targetAuthorNumber"
|
||||
)
|
||||
or ""
|
||||
),
|
||||
remove=bool(reaction_payload.get("remove")),
|
||||
@@ -741,9 +755,7 @@ class HandleMessage(Command):
|
||||
remove=bool(reaction_payload.get("remove")),
|
||||
upstream_message_id="",
|
||||
upstream_ts=int(reaction_payload.get("target_ts") or 0),
|
||||
actor=(
|
||||
effective_source_uuid or effective_source_number or ""
|
||||
),
|
||||
actor=(effective_source_uuid or effective_source_number or ""),
|
||||
payload=reaction_payload.get("raw") or {},
|
||||
)
|
||||
except Exception as exc:
|
||||
@@ -840,9 +852,7 @@ class HandleMessage(Command):
|
||||
source_ref={
|
||||
"upstream_message_id": "",
|
||||
"upstream_author": str(
|
||||
effective_source_uuid
|
||||
or effective_source_number
|
||||
or ""
|
||||
effective_source_uuid or effective_source_number or ""
|
||||
),
|
||||
"upstream_ts": int(ts or 0),
|
||||
},
|
||||
@@ -1134,7 +1144,9 @@ class SignalClient(ClientBase):
|
||||
if int(message_row.delivered_ts or 0) <= 0:
|
||||
message_row.delivered_ts = int(result)
|
||||
update_fields.append("delivered_ts")
|
||||
if str(message_row.source_message_id or "").strip() != str(result):
|
||||
if str(message_row.source_message_id or "").strip() != str(
|
||||
result
|
||||
):
|
||||
message_row.source_message_id = str(result)
|
||||
update_fields.append("source_message_id")
|
||||
if update_fields:
|
||||
@@ -1146,9 +1158,11 @@ class SignalClient(ClientBase):
|
||||
command_id,
|
||||
{
|
||||
"ok": True,
|
||||
"timestamp": int(result)
|
||||
if isinstance(result, int)
|
||||
else int(time.time() * 1000),
|
||||
"timestamp": (
|
||||
int(result)
|
||||
if isinstance(result, int)
|
||||
else int(time.time() * 1000)
|
||||
),
|
||||
},
|
||||
)
|
||||
except Exception as exc:
|
||||
@@ -1248,7 +1262,9 @@ class SignalClient(ClientBase):
|
||||
if _digits_only(getattr(row, "identifier", "")) in candidate_digits
|
||||
]
|
||||
|
||||
async def _auto_link_single_user_signal_identifier(self, source_uuid: str, source_number: str):
|
||||
async def _auto_link_single_user_signal_identifier(
|
||||
self, source_uuid: str, source_number: str
|
||||
):
|
||||
owner_rows = await sync_to_async(list)(
|
||||
PersonIdentifier.objects.filter(service=self.service)
|
||||
.select_related("user")
|
||||
@@ -1292,7 +1308,9 @@ class SignalClient(ClientBase):
|
||||
payload = json.loads(raw_message or "{}")
|
||||
except Exception:
|
||||
return
|
||||
exception_payload = payload.get("exception") if isinstance(payload, dict) else None
|
||||
exception_payload = (
|
||||
payload.get("exception") if isinstance(payload, dict) else None
|
||||
)
|
||||
if isinstance(exception_payload, dict):
|
||||
err_type = str(exception_payload.get("type") or "").strip()
|
||||
err_msg = str(exception_payload.get("message") or "").strip()
|
||||
@@ -1322,7 +1340,9 @@ class SignalClient(ClientBase):
|
||||
(envelope.get("timestamp") if isinstance(envelope, dict) else 0)
|
||||
or int(time.time() * 1000)
|
||||
),
|
||||
last_inbound_exception_account=str(payload.get("account") or "").strip(),
|
||||
last_inbound_exception_account=str(
|
||||
payload.get("account") or ""
|
||||
).strip(),
|
||||
last_inbound_exception_source_uuid=envelope_source_uuid,
|
||||
last_inbound_exception_source_number=envelope_source_number,
|
||||
last_inbound_exception_envelope_ts=envelope_ts,
|
||||
@@ -1346,7 +1366,11 @@ class SignalClient(ClientBase):
|
||||
raw_text = sync_sent_message.get("message")
|
||||
if isinstance(raw_text, dict):
|
||||
text = _extract_signal_text(
|
||||
{"envelope": {"syncMessage": {"sentMessage": {"message": raw_text}}}},
|
||||
{
|
||||
"envelope": {
|
||||
"syncMessage": {"sentMessage": {"message": raw_text}}
|
||||
}
|
||||
},
|
||||
str(
|
||||
raw_text.get("message")
|
||||
or raw_text.get("text")
|
||||
@@ -1396,9 +1420,15 @@ class SignalClient(ClientBase):
|
||||
source_service="signal",
|
||||
actor=(source_uuid or source_number or ""),
|
||||
target_author=str(
|
||||
(reaction_payload.get("raw") or {}).get("targetAuthorUuid")
|
||||
or (reaction_payload.get("raw") or {}).get("targetAuthor")
|
||||
or (reaction_payload.get("raw") or {}).get("targetAuthorNumber")
|
||||
(reaction_payload.get("raw") or {}).get(
|
||||
"targetAuthorUuid"
|
||||
)
|
||||
or (reaction_payload.get("raw") or {}).get(
|
||||
"targetAuthor"
|
||||
)
|
||||
or (reaction_payload.get("raw") or {}).get(
|
||||
"targetAuthorNumber"
|
||||
)
|
||||
or ""
|
||||
),
|
||||
remove=bool(reaction_payload.get("remove")),
|
||||
@@ -1505,7 +1535,9 @@ class SignalClient(ClientBase):
|
||||
source_chat_id = destination_number or destination_uuid or sender_key
|
||||
reply_ref = reply_sync.extract_reply_ref(self.service, payload)
|
||||
for identifier in identifiers:
|
||||
session = await history.get_chat_session(identifier.user, identifier)
|
||||
session = await history.get_chat_session(
|
||||
identifier.user, identifier
|
||||
)
|
||||
reply_target = await reply_sync.resolve_reply_target(
|
||||
identifier.user,
|
||||
session,
|
||||
@@ -1552,13 +1584,19 @@ class SignalClient(ClientBase):
|
||||
if not isinstance(data_message, dict):
|
||||
return
|
||||
|
||||
source_uuid = str(envelope.get("sourceUuid") or envelope.get("source") or "").strip()
|
||||
source_uuid = str(
|
||||
envelope.get("sourceUuid") or envelope.get("source") or ""
|
||||
).strip()
|
||||
source_number = str(envelope.get("sourceNumber") or "").strip()
|
||||
bot_uuid = str(getattr(self.client, "bot_uuid", "") or "").strip()
|
||||
bot_phone = str(getattr(self.client, "phone_number", "") or "").strip()
|
||||
if source_uuid and bot_uuid and source_uuid == bot_uuid:
|
||||
return
|
||||
if source_number and bot_phone and _digits_only(source_number) == _digits_only(bot_phone):
|
||||
if (
|
||||
source_number
|
||||
and bot_phone
|
||||
and _digits_only(source_number) == _digits_only(bot_phone)
|
||||
):
|
||||
return
|
||||
|
||||
identifiers = await self._resolve_signal_identifiers(source_uuid, source_number)
|
||||
@@ -1610,14 +1648,18 @@ class SignalClient(ClientBase):
|
||||
target_author=str(
|
||||
(reaction_payload.get("raw") or {}).get("targetAuthorUuid")
|
||||
or (reaction_payload.get("raw") or {}).get("targetAuthor")
|
||||
or (reaction_payload.get("raw") or {}).get("targetAuthorNumber")
|
||||
or (reaction_payload.get("raw") or {}).get(
|
||||
"targetAuthorNumber"
|
||||
)
|
||||
or ""
|
||||
),
|
||||
remove=bool(reaction_payload.get("remove")),
|
||||
payload=reaction_payload.get("raw") or {},
|
||||
)
|
||||
except Exception as exc:
|
||||
self.log.warning("signal raw reaction history apply failed: %s", exc)
|
||||
self.log.warning(
|
||||
"signal raw reaction history apply failed: %s", exc
|
||||
)
|
||||
try:
|
||||
await self.ur.xmpp.client.apply_external_reaction(
|
||||
identifier.user,
|
||||
@@ -1631,7 +1673,9 @@ class SignalClient(ClientBase):
|
||||
payload=reaction_payload.get("raw") or {},
|
||||
)
|
||||
except Exception as exc:
|
||||
self.log.warning("signal raw reaction relay to XMPP failed: %s", exc)
|
||||
self.log.warning(
|
||||
"signal raw reaction relay to XMPP failed: %s", exc
|
||||
)
|
||||
transport.update_runtime_state(
|
||||
self.service,
|
||||
last_inbound_ok_ts=int(time.time() * 1000),
|
||||
@@ -1683,7 +1727,9 @@ class SignalClient(ClientBase):
|
||||
)
|
||||
return
|
||||
|
||||
text = _extract_signal_text(payload, str(data_message.get("message") or "").strip())
|
||||
text = _extract_signal_text(
|
||||
payload, str(data_message.get("message") or "").strip()
|
||||
)
|
||||
if not text:
|
||||
return
|
||||
|
||||
@@ -1702,7 +1748,11 @@ class SignalClient(ClientBase):
|
||||
or envelope.get("timestamp")
|
||||
or ts
|
||||
).strip()
|
||||
sender_key = source_uuid or source_number or (identifiers[0].identifier if identifiers else "")
|
||||
sender_key = (
|
||||
source_uuid
|
||||
or source_number
|
||||
or (identifiers[0].identifier if identifiers else "")
|
||||
)
|
||||
source_chat_id = source_number or source_uuid or sender_key
|
||||
reply_ref = reply_sync.extract_reply_ref(self.service, payload)
|
||||
|
||||
|
||||
@@ -927,7 +927,11 @@ async def send_reaction(
|
||||
service_key = _service_key(service)
|
||||
if _capability_checks_enabled() and not supports(service_key, "reactions"):
|
||||
reason = unsupported_reason(service_key, "reactions")
|
||||
log.warning("capability-check failed service=%s feature=reactions: %s", service_key, reason)
|
||||
log.warning(
|
||||
"capability-check failed service=%s feature=reactions: %s",
|
||||
service_key,
|
||||
reason,
|
||||
)
|
||||
return False
|
||||
if not str(emoji or "").strip() and not remove:
|
||||
return False
|
||||
|
||||
@@ -173,9 +173,7 @@ class WhatsAppClient(ClientBase):
|
||||
if db_dir:
|
||||
os.makedirs(db_dir, exist_ok=True)
|
||||
if db_dir and not os.access(db_dir, os.W_OK):
|
||||
raise PermissionError(
|
||||
f"session db directory is not writable: {db_dir}"
|
||||
)
|
||||
raise PermissionError(f"session db directory is not writable: {db_dir}")
|
||||
except Exception as exc:
|
||||
self._publish_state(
|
||||
connected=False,
|
||||
@@ -772,9 +770,11 @@ class WhatsAppClient(ClientBase):
|
||||
command_id,
|
||||
{
|
||||
"ok": True,
|
||||
"timestamp": int(result)
|
||||
if isinstance(result, int)
|
||||
else int(time.time() * 1000),
|
||||
"timestamp": (
|
||||
int(result)
|
||||
if isinstance(result, int)
|
||||
else int(time.time() * 1000)
|
||||
),
|
||||
},
|
||||
)
|
||||
self.log.debug(
|
||||
@@ -1910,9 +1910,7 @@ class WhatsAppClient(ClientBase):
|
||||
jid_value = self._jid_to_identifier(
|
||||
self._pluck(group, "JID") or self._pluck(group, "jid")
|
||||
)
|
||||
identifier = (
|
||||
jid_value.split("@", 1)[0].strip() if jid_value else ""
|
||||
)
|
||||
identifier = jid_value.split("@", 1)[0].strip() if jid_value else ""
|
||||
if not identifier:
|
||||
continue
|
||||
name = (
|
||||
@@ -2362,12 +2360,22 @@ class WhatsAppClient(ClientBase):
|
||||
node = (
|
||||
self._pluck(message_obj, "reactionMessage")
|
||||
or self._pluck(message_obj, "reaction_message")
|
||||
or self._pluck(message_obj, "ephemeralMessage", "message", "reactionMessage")
|
||||
or self._pluck(message_obj, "ephemeral_message", "message", "reaction_message")
|
||||
or self._pluck(
|
||||
message_obj, "ephemeralMessage", "message", "reactionMessage"
|
||||
)
|
||||
or self._pluck(
|
||||
message_obj, "ephemeral_message", "message", "reaction_message"
|
||||
)
|
||||
or self._pluck(message_obj, "viewOnceMessage", "message", "reactionMessage")
|
||||
or self._pluck(message_obj, "view_once_message", "message", "reaction_message")
|
||||
or self._pluck(message_obj, "viewOnceMessageV2", "message", "reactionMessage")
|
||||
or self._pluck(message_obj, "view_once_message_v2", "message", "reaction_message")
|
||||
or self._pluck(
|
||||
message_obj, "view_once_message", "message", "reaction_message"
|
||||
)
|
||||
or self._pluck(
|
||||
message_obj, "viewOnceMessageV2", "message", "reactionMessage"
|
||||
)
|
||||
or self._pluck(
|
||||
message_obj, "view_once_message_v2", "message", "reaction_message"
|
||||
)
|
||||
or self._pluck(
|
||||
message_obj,
|
||||
"viewOnceMessageV2Extension",
|
||||
@@ -2410,7 +2418,9 @@ class WhatsAppClient(ClientBase):
|
||||
explicit_remove = self._pluck(node, "remove") or self._pluck(node, "isRemove")
|
||||
if explicit_remove is None:
|
||||
explicit_remove = self._pluck(node, "is_remove")
|
||||
remove = bool(explicit_remove) if explicit_remove is not None else bool(not emoji)
|
||||
remove = (
|
||||
bool(explicit_remove) if explicit_remove is not None else bool(not emoji)
|
||||
)
|
||||
if not target_msg_id:
|
||||
return None
|
||||
return {
|
||||
@@ -2418,7 +2428,11 @@ class WhatsAppClient(ClientBase):
|
||||
"target_message_id": target_msg_id,
|
||||
"remove": remove,
|
||||
"target_ts": int(target_ts or 0),
|
||||
"raw": self._proto_to_dict(node) or dict(node or {}) if isinstance(node, dict) else {},
|
||||
"raw": (
|
||||
self._proto_to_dict(node) or dict(node or {})
|
||||
if isinstance(node, dict)
|
||||
else {}
|
||||
),
|
||||
}
|
||||
|
||||
async def _download_event_media(self, event):
|
||||
@@ -2760,7 +2774,9 @@ class WhatsAppClient(ClientBase):
|
||||
or self._pluck(msg_obj, "MessageContextInfo")
|
||||
or {},
|
||||
"message": {
|
||||
"extendedTextMessage": self._pluck(msg_obj, "extendedTextMessage")
|
||||
"extendedTextMessage": self._pluck(
|
||||
msg_obj, "extendedTextMessage"
|
||||
)
|
||||
or self._pluck(msg_obj, "ExtendedTextMessage")
|
||||
or {},
|
||||
"imageMessage": self._pluck(msg_obj, "imageMessage") or {},
|
||||
@@ -2768,9 +2784,9 @@ class WhatsAppClient(ClientBase):
|
||||
"videoMessage": self._pluck(msg_obj, "videoMessage") or {},
|
||||
"VideoMessage": self._pluck(msg_obj, "VideoMessage") or {},
|
||||
"documentMessage": self._pluck(msg_obj, "documentMessage")
|
||||
or {},
|
||||
or {},
|
||||
"DocumentMessage": self._pluck(msg_obj, "DocumentMessage")
|
||||
or {},
|
||||
or {},
|
||||
"ephemeralMessage": self._pluck(msg_obj, "ephemeralMessage")
|
||||
or {},
|
||||
"EphemeralMessage": self._pluck(msg_obj, "EphemeralMessage")
|
||||
@@ -2814,7 +2830,9 @@ class WhatsAppClient(ClientBase):
|
||||
or {},
|
||||
"viewOnceMessage": self._pluck(msg_obj, "viewOnceMessage")
|
||||
or {},
|
||||
"viewOnceMessageV2": self._pluck(msg_obj, "viewOnceMessageV2")
|
||||
"viewOnceMessageV2": self._pluck(
|
||||
msg_obj, "viewOnceMessageV2"
|
||||
)
|
||||
or {},
|
||||
"viewOnceMessageV2Extension": self._pluck(
|
||||
msg_obj, "viewOnceMessageV2Extension"
|
||||
@@ -2840,12 +2858,12 @@ class WhatsAppClient(ClientBase):
|
||||
reply_sync.extract_origin_tag(payload),
|
||||
)
|
||||
if self._chat_matches_reply_debug(chat):
|
||||
info_obj = self._proto_to_dict(self._pluck(event_obj, "Info")) or self._pluck(
|
||||
event_obj, "Info"
|
||||
)
|
||||
raw_obj = self._proto_to_dict(self._pluck(event_obj, "Raw")) or self._pluck(
|
||||
event_obj, "Raw"
|
||||
)
|
||||
info_obj = self._proto_to_dict(
|
||||
self._pluck(event_obj, "Info")
|
||||
) or self._pluck(event_obj, "Info")
|
||||
raw_obj = self._proto_to_dict(
|
||||
self._pluck(event_obj, "Raw")
|
||||
) or self._pluck(event_obj, "Raw")
|
||||
message_meta["wa_reply_debug"] = {
|
||||
"reply_ref": reply_ref,
|
||||
"reply_target_id": str(getattr(reply_target, "id", "") or ""),
|
||||
@@ -3087,9 +3105,11 @@ class WhatsAppClient(ClientBase):
|
||||
)
|
||||
matched = False
|
||||
for candidate in candidates:
|
||||
candidate_local = str(self._jid_to_identifier(candidate) or "").split(
|
||||
"@", 1
|
||||
)[0].strip()
|
||||
candidate_local = (
|
||||
str(self._jid_to_identifier(candidate) or "")
|
||||
.split("@", 1)[0]
|
||||
.strip()
|
||||
)
|
||||
if candidate_local and candidate_local == local:
|
||||
matched = True
|
||||
break
|
||||
@@ -3124,7 +3144,12 @@ class WhatsAppClient(ClientBase):
|
||||
# WhatsApp group ids are numeric and usually very long (commonly start
|
||||
# with 120...). Treat those as groups when no explicit mapping exists.
|
||||
digits = re.sub(r"[^0-9]", "", local)
|
||||
if digits and digits == local and len(digits) >= 15 and digits.startswith("120"):
|
||||
if (
|
||||
digits
|
||||
and digits == local
|
||||
and len(digits) >= 15
|
||||
and digits.startswith("120")
|
||||
):
|
||||
return f"{digits}@g.us"
|
||||
return ""
|
||||
|
||||
@@ -3264,7 +3289,9 @@ class WhatsAppClient(ClientBase):
|
||||
person_identifier = await sync_to_async(
|
||||
lambda: (
|
||||
Message.objects.filter(id=legacy_message_id)
|
||||
.select_related("session__identifier__user", "session__identifier__person")
|
||||
.select_related(
|
||||
"session__identifier__user", "session__identifier__person"
|
||||
)
|
||||
.first()
|
||||
)
|
||||
)()
|
||||
@@ -3274,7 +3301,9 @@ class WhatsAppClient(ClientBase):
|
||||
)
|
||||
if (
|
||||
person_identifier is not None
|
||||
and str(getattr(person_identifier, "service", "") or "").strip().lower()
|
||||
and str(getattr(person_identifier, "service", "") or "")
|
||||
.strip()
|
||||
.lower()
|
||||
!= "whatsapp"
|
||||
):
|
||||
person_identifier = None
|
||||
@@ -3418,6 +3447,8 @@ class WhatsAppClient(ClientBase):
|
||||
from neonize.proto.waE2E.WAWebProtobufsE2E_pb2 import (
|
||||
ContextInfo,
|
||||
ExtendedTextMessage,
|
||||
)
|
||||
from neonize.proto.waE2E.WAWebProtobufsE2E_pb2 import (
|
||||
Message as WAProtoMessage,
|
||||
)
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user