Merge pull request #5362 from dannysmyda/5682-simplify-app-db-queries

5682 simplify app db queries
This commit is contained in:
Richard Cordovano 2019-10-23 12:46:15 -04:00 committed by GitHub
commit bc21a24caf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 137 additions and 216 deletions

View File

@ -236,28 +236,23 @@ class LineCallLogsParser(TskCallLogsParser):
def __init__(self, calllog_db):
super(LineCallLogsParser, self).__init__(calllog_db.runQuery(
"""
SELECT Substr(CH.call_type, -1) AS direction,
CH.start_time AS start_time,
CH.end_time AS end_time,
contacts_list_with_groups.members AS group_members,
contacts_list_with_groups.member_names AS names,
CH.caller_mid,
CH.voip_type AS call_type,
CH.voip_gc_media_type AS group_call_type
SELECT Substr(calls.call_type, -1) AS direction,
calls.start_time AS start_time,
calls.end_time AS end_time,
contact_book_w_groups.members AS group_members,
calls.caller_mid,
calls.voip_type AS call_type,
calls.voip_gc_media_type AS group_call_type
FROM (SELECT id,
Group_concat(M.m_id) AS members,
Group_concat(Replace(C.server_name, ",", "")) AS member_names
Group_concat(M.m_id) AS members
FROM membership AS M
JOIN naver.contacts AS C
ON M.m_id = C.m_id
GROUP BY id
UNION
SELECT m_id,
NULL,
server_name
FROM naver.contacts) AS contacts_list_with_groups
JOIN call_history AS CH
ON CH.caller_mid = contacts_list_with_groups.id
NULL
FROM naver.contacts) AS contact_book_w_groups
JOIN call_history AS calls
ON calls.caller_mid = contact_book_w_groups.id
"""
)
)
@ -355,42 +350,24 @@ class LineMessagesParser(TskMessagesParser):
def __init__(self, message_db):
super(LineMessagesParser, self).__init__(message_db.runQuery(
"""
SELECT contact_list_with_groups.name,
contact_list_with_groups.id,
contact_list_with_groups.members,
contact_list_with_groups.member_names,
CH.from_mid,
C.server_name AS from_name,
CH.content,
CH.created_time,
CH.attachement_type,
CH.attachement_local_uri,
CH.status
FROM (SELECT G.name,
group_members.id,
group_members.members,
group_members.member_names
SELECT contact_book_w_groups.id,
contact_book_w_groups.members,
messages.from_mid,
messages.content,
messages.created_time,
messages.attachement_type,
messages.attachement_local_uri,
messages.status
FROM (SELECT id,
group_concat(M.m_id) AS members,
group_concat(replace(C.server_name,
",",
"")) as member_names
Group_concat(M.m_id) AS members
FROM membership AS M
JOIN contacts as C
ON M.m_id = C.m_id
GROUP BY id) AS group_members
JOIN groups AS G
ON G.id = group_members.id
GROUP BY id
UNION
SELECT server_name,
m_id,
NULL,
SELECT m_id,
NULL
FROM contacts) AS contact_list_with_groups
JOIN chat_history AS CH
ON CH.chat_id = contact_list_with_groups.id
LEFT JOIN contacts as C
ON C.m_id = CH.from_mid
FROM contacts) AS contact_book_w_groups
JOIN chat_history AS messages
ON messages.chat_id = contact_book_w_groups.id
WHERE attachement_type != 6
"""
)

View File

@ -76,11 +76,8 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer):
as they would be excluded in the join. Since the chatItem table stores both the
group id or skype_id in one column, an implementation decision was made to union
the person and particiapnt table together so that all rows are matched in one join
with chatItem. This result is consistently labeled contact_list_with_groups in the
with chatItem. This result is consistently labeled contact_book_w_groups in the
following queries.
- In order to keep the formatting of the name consistent throughout each query,
a _format_user_name() function was created to encapsulate the CASE statement
that was being shared across them. Refer to the method for more details.
"""
def __init__(self):
@ -93,7 +90,12 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer):
account_query_result = skype_db.runQuery(
"""
SELECT entry_id,
"""+_format_user_name()+""" AS name
CASE
WHEN Ifnull(first_name, "") == "" AND Ifnull(last_name, "") == "" THEN entry_id
WHEN first_name is NULL THEN replace(last_name, ",", "")
WHEN last_name is NULL THEN replace(first_name, ",", "")
ELSE replace(first_name, ",", "") || " " || replace(last_name, ",", "")
END AS name
FROM user
"""
)
@ -251,14 +253,6 @@ class SkypeCallLogsParser(TskCallLogsParser):
def __init__(self, calllog_db):
"""
Big picture:
The query below creates a contacts_list_with_groups table, which
represents the recipient info. A chatItem record holds ids for
both the recipient and sender. The first join onto chatItem fills
in the blanks for the recipients. The second join back onto person
handles the sender info. The result is a table with all of the
communication details.
Implementation details:
- message_type w/ value 3 appeared to be the call type, regardless
of if it was audio or video.
@ -266,36 +260,22 @@ class SkypeCallLogsParser(TskCallLogsParser):
"""
super(SkypeCallLogsParser, self).__init__(calllog_db.runQuery(
"""
SELECT contacts_list_with_groups.conversation_id,
contacts_list_with_groups.participant_ids,
contacts_list_with_groups.participants,
time,
duration,
is_sender_me,
person_id as sender_id,
sender_name.name as sender_name
SELECT contact_book_w_groups.conversation_id,
contact_book_w_groups.participant_ids,
messages.time,
messages.duration,
messages.is_sender_me,
messages.person_id AS sender_id
FROM (SELECT conversation_id,
Group_concat(person_id) AS participant_ids,
Group_concat("""+_format_user_name()+""") AS participants
FROM particiapnt AS PART
JOIN person AS P
ON PART.person_id = P.entry_id
Group_concat(person_id) AS participant_ids
FROM particiapnt
GROUP BY conversation_id
UNION
SELECT entry_id,
NULL,
"""+_format_user_name()+""" AS participant
FROM person) AS contacts_list_with_groups
JOIN chatitem AS C
ON C.conversation_link = contacts_list_with_groups.conversation_id
JOIN (SELECT entry_id as id,
"""+_format_user_name()+""" AS name
FROM person
UNION
SELECT entry_id as id,
"""+_format_user_name()+""" AS name
FROM user) AS sender_name
ON sender_name.id = C.person_id
SELECT entry_id AS conversation_id,
NULL
FROM person) AS contact_book_w_groups
join chatitem AS messages
ON messages.conversation_link = contact_book_w_groups.conversation_id
WHERE message_type == 3
"""
)
@ -347,7 +327,12 @@ class SkypeContactsParser(TskContactsParser):
super(SkypeContactsParser, self).__init__(contact_db.runQuery(
"""
SELECT entry_id,
"""+_format_user_name()+""" AS name
CASE
WHEN Ifnull(first_name, "") == "" AND Ifnull(last_name, "") == "" THEN entry_id
WHEN first_name is NULL THEN replace(last_name, ",", "")
WHEN last_name is NULL THEN replace(first_name, ",", "")
ELSE replace(first_name, ",", "") || " " || replace(last_name, ",", "")
END AS name
FROM person
"""
)
@ -379,37 +364,23 @@ class SkypeMessagesParser(TskMessagesParser):
"""
super(SkypeMessagesParser, self).__init__(message_db.runQuery(
"""
SELECT contacts_list_with_groups.conversation_id,
contacts_list_with_groups.participant_ids,
contacts_list_with_groups.participants,
time,
content,
device_gallery_path,
is_sender_me,
person_id as sender_id,
sender_name.name AS sender_name
SELECT contact_book_w_groups.conversation_id,
contact_book_w_groups.participant_ids,
messages.time,
messages.content,
messages.device_gallery_path,
messages.is_sender_me,
messages.person_id as sender_id
FROM (SELECT conversation_id,
Group_concat(person_id) AS participant_ids,
Group_concat("""+_format_user_name()+""") AS participants
FROM particiapnt AS PART
JOIN person AS P
ON PART.person_id = P.entry_id
Group_concat(person_id) AS participant_ids
FROM particiapnt
GROUP BY conversation_id
UNION
SELECT entry_id as conversation_id,
NULL,
"""+_format_user_name()+""" AS participant
FROM person) AS contacts_list_with_groups
JOIN chatitem AS C
ON C.conversation_link = contacts_list_with_groups.conversation_id
JOIN (SELECT entry_id as id,
"""+_format_user_name()+""" AS name
FROM person
UNION
SELECT entry_id as id,
"""+_format_user_name()+""" AS name
FROM user) AS sender_name
ON sender_name.id = C.person_id
NULL
FROM person) AS contact_book_w_groups
JOIN chatitem AS messages
ON messages.conversation_link = contact_book_w_groups.conversation_id
WHERE message_type != 3
"""
)
@ -469,25 +440,3 @@ class SkypeMessagesParser(TskMessagesParser):
if group_ids is not None:
return self.result_set.getString("conversation_id")
return super(SkypeMessagesParser, self).get_thread_id()
def _format_user_name():
"""
This CASE SQL statement is used in many queries to
format the names of users. For a user, there is a first_name
column and a last_name column. Some of these columns can be null
and our goal is to produce the cleanest data possible. In the event
that both the first and last name columns are null, we return the skype_id
which is stored in the database as 'entry_id'. Commas are removed from the name
so that we can concatenate names into a comma seperate list for group chats.
"""
return """
CASE
WHEN Ifnull(first_name, "") == "" AND Ifnull(last_name, "") == "" THEN entry_id
WHEN first_name is NULL THEN replace(last_name, ",", "")
WHEN last_name is NULL THEN replace(first_name, ",", "")
ELSE replace(first_name, ",", "") || " " || replace(last_name, ",", "")
END
"""

View File

@ -290,39 +290,37 @@ class TextNowMessagesParser(TskMessagesParser):
"""
super(TextNowMessagesParser, self).__init__(message_db.runQuery(
"""
SELECT CASE
WHEN message_direction == 2 THEN ""
WHEN to_addresses IS NULL THEN M.contact_value
ELSE contact_name
end from_address,
WHEN messages.message_direction == 2 THEN NULL
WHEN contact_book_w_groups.to_addresses IS NULL THEN
messages.contact_value
END from_address,
CASE
WHEN message_direction == 1 THEN ""
WHEN to_addresses IS NULL THEN M.contact_value
ELSE to_addresses
end to_address,
message_direction,
message_text,
M.READ,
M.date,
M.attach,
WHEN messages.message_direction == 1 THEN NULL
WHEN contact_book_w_groups.to_addresses IS NULL THEN
messages.contact_value
ELSE contact_book_w_groups.to_addresses
END to_address,
messages.message_direction,
messages.message_text,
messages.READ,
messages.DATE,
messages.attach,
thread_id
FROM (SELECT group_info.contact_value,
group_info.to_addresses,
G.contact_value AS thread_id
FROM (SELECT GM.contact_value,
Group_concat(GM.member_contact_value) AS to_addresses
Group_concat(GM.member_contact_value) AS to_addresses,
G.contact_value AS thread_id
FROM group_members AS GM
GROUP BY GM.contact_value) AS group_info
JOIN groups AS G
ON G.contact_value = group_info.contact_value
join GROUPS AS G
ON G.contact_value = GM.contact_value
GROUP BY GM.contact_value
UNION
SELECT c.contact_value,
SELECT contact_value,
NULL,
"-1"
FROM contacts AS c) AS to_from_map
JOIN messages AS M
ON M.contact_value = to_from_map.contact_value
NULL
FROM contacts) AS contact_book_w_groups
join messages
ON messages.contact_value = contact_book_w_groups.contact_value
WHERE message_type NOT IN ( 102, 100 )
"""
)
@ -330,13 +328,12 @@ class TextNowMessagesParser(TskMessagesParser):
self._TEXTNOW_MESSAGE_TYPE = "TextNow Message"
self._INCOMING_MESSAGE_TYPE = 1
self._OUTGOING_MESSAGE_TYPE = 2
self._UNKNOWN_THREAD_ID = "-1"
def get_message_type(self):
return self._TEXTNOW_MESSAGE_TYPE
def get_phone_number_from(self):
if self.result_set.getString("from_address") == "":
if self.result_set.getString("from_address") is None:
return super(TextNowMessagesParser, self).get_phone_number_from()
return self.result_set.getString("from_address")
@ -347,10 +344,9 @@ class TextNowMessagesParser(TskMessagesParser):
return self.OUTGOING
def get_phone_number_to(self):
if self.result_set.getString("to_address") == "":
if self.result_set.getString("to_address") is None:
return super(TextNowMessagesParser, self).get_phone_number_to()
recipients = self.result_set.getString("to_address").split(",")
return recipients
return self.result_set.getString("to_address").split(",")
def get_message_date_time(self):
#convert ms to s
@ -359,7 +355,7 @@ class TextNowMessagesParser(TskMessagesParser):
def get_message_read_status(self):
read = self.result_set.getBoolean("read")
if self.get_message_direction() == self.INCOMING:
if read == True:
if read:
return self.READ
return self.UNREAD
@ -375,6 +371,6 @@ class TextNowMessagesParser(TskMessagesParser):
def get_thread_id(self):
thread_id = self.result_set.getString("thread_id")
if thread_id == self._UNKNOWN_THREAD_ID:
if thread_id is None:
return super(TextNowMessagesParser, self).get_thread_id()
return thread_id

View File

@ -433,31 +433,28 @@ class WhatsAppMessagesParser(TskMessagesParser):
def __init__(self, message_db):
super(WhatsAppMessagesParser, self).__init__(message_db.runQuery(
"""
SELECT M.key_remote_jid AS id,
contact_info.recipients,
SELECT messages.key_remote_jid AS id,
contact_book_w_groups.recipients,
key_from_me AS direction,
CASE
WHEN M.data IS NULL THEN ""
ELSE M.data
END AS content,
M.timestamp AS send_timestamp,
M.received_timestamp,
M.remote_resource AS group_sender,
M.media_url As attachment
messages.data AS content,
messages.timestamp AS send_timestamp,
messages.received_timestamp,
messages.remote_resource AS group_sender,
messages.media_url AS attachment
FROM (SELECT jid,
recipients
FROM wadb.wa_contacts AS WC
LEFT JOIN (SELECT gjid,
group_concat(CASE
FROM wadb.wa_contacts AS contacts
left join (SELECT gjid,
Group_concat(CASE
WHEN jid == "" THEN NULL
ELSE jid
END) AS recipients
FROM group_participants
GROUP BY gjid) AS group_map
ON WC.jid = group_map.gjid
GROUP BY jid) AS contact_info
JOIN messages AS M
ON M.key_remote_jid = contact_info.jid
GROUP BY gjid) AS groups
ON contacts.jid = groups.gjid
GROUP BY jid) AS contact_book_w_groups
join messages
ON messages.key_remote_jid = contact_book_w_groups.jid
"""
)
)
@ -503,6 +500,8 @@ class WhatsAppMessagesParser(TskMessagesParser):
def get_message_text(self):
message = self.result_set.getString("content")
if message is None:
message = super(WhatsAppMessagesParser, self).get_message_text()
attachment = self.result_set.getString("attachment")
if attachment is not None:
return general.appendAttachmentList(message, [attachment])