Explorar o código

Add util/apple_timestamp.js, centralizing Apple timestamp parsing.

Tanel Karindi %!s(int64=6) %!d(string=hai) anos
pai
achega
18c4cc0008

+ 4 - 0
tools/reports/calendar/events.js

@@ -1,5 +1,6 @@
 // Derive filenames based on domain + file path
 const fileHash = require('../../util/backup_filehash')
+const apple_timestamp = require('../../util/apple_timestamp')
 
 const CAL_DB = fileHash('Library/Calendar/Calendar.sqlitedb')
 
@@ -17,6 +18,7 @@ module.exports = {
   // Fields for apps report
   output: {
     timestamp: el => (new Date((el.start_date + 978307200) * 1000).toDateString()) + ' ' + (new Date((el.start_date + 978307200) * 1000).toTimeString()),
+    timestamp_string: el => el.start_date_string,  
     title: el => el.summary,
     content: el => el.description,
     calendarId: el => el.calendar_id,
@@ -31,6 +33,8 @@ function calendarReport (backup) {
         const query = `
         SELECT
           CalendarItem.*,
+          ${apple_timestamp.parse('CalendarItem.start_date')} AS start_date_string,
+
           Calendar.title as calendar_title
         FROM CalendarItem
         LEFT JOIN Calendar ON

+ 3 - 2
tools/reports/messages/conversations.js

@@ -2,6 +2,7 @@ const bplist = require('bplist-parser')
 
 const fileHash = require('../../util/backup_filehash')
 const log = require('../../util/log')
+const apple_timestamp = require('../../util/apple_timestamp')
 
 const SMS_DB = fileHash('Library/SMS/sms.db')
 
@@ -74,10 +75,10 @@ function getConversationsiOS9 (backup) {
 }
 
 function getConversationsiOS10iOS11 (backup) {
-  return new Promise((resolve, reject) => {
+    return new Promise((resolve, reject) => {
     backup.openDatabase(SMS_DB)
       .then(db => {
-        db.all(`SELECT *, datetime(last_read_message_timestamp / 1000000000 + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING FROM chat ORDER BY last_read_message_timestamp ASC`, async function (err, rows) {
+        db.all(`SELECT *, ${apple_timestamp.parse('last_read_message_timestamp')} AS XFORMATTEDDATESTRING FROM chat ORDER BY last_read_message_timestamp ASC`, async function (err, rows) {
           if (err) return reject(err)
           rows = rows || []
 

+ 6 - 6
tools/reports/messages/messages.js

@@ -1,6 +1,6 @@
 const fileHash = require('../../util/backup_filehash')
 const log = require('../../util/log')
-
+const apple_timestamp = require('../../util/apple_timestamp')
 const SMS_DB = fileHash('Library/SMS/sms.db')
 
 module.exports = {
@@ -23,7 +23,7 @@ module.exports = {
   // Available fields.
   output: {
     id: el => el.ROWID,
-    date: el => el.XFORMATTEDDATESTRING,
+    date: el => el.date,
     sender: el => el.x_sender,
     text: el => (el.text || '').trim(),
     dateRead: el => el.date_read + '',
@@ -65,7 +65,7 @@ function getMessagesiOS9 (backup, chatId) {
       SELECT 
         message.*,
         handle.id as sender_name,
-        datetime(date + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING
+        ${apple_timestamp.parse(date)} AS date
       FROM chat_message_join 
       INNER JOIN message 
         ON message.rowid = chat_message_join.message_id 
@@ -106,9 +106,9 @@ function getMessagesiOS10iOS11 (backup, chatId) {
       SELECT 
         message.*,
         handle.id as sender_name,
-        datetime((date_read + 978307200), 'unixepoch') as date_read,
-        datetime((date_delivered + 978307200), 'unixepoch') as date_delivered,
-        datetime(date / 1000000000 + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING
+        ${apple_timestamp.parse('date_read')} AS date_read,
+        ${apple_timestamp.parse('date_delivered')} AS date_delivered,
+        ${apple_timestamp.parse('date')} AS date
       FROM chat_message_join 
       INNER JOIN message 
         ON message.rowid = chat_message_join.message_id 

+ 4 - 3
tools/reports/notes/notes.js

@@ -1,5 +1,6 @@
 const fileHash = require('../../util/backup_filehash')
 const log = require('../../util/log')
+const apple_timestamp = require('../../util/apple_timestamp')
 
 const NOTES_DB = fileHash('Library/Notes/notes.sqlite')
 const NOTES2_DB = fileHash('NoteStore.sqlite', 'AppDomainGroup-group.com.apple.notes')
@@ -71,7 +72,7 @@ function getNewNotesiOS9 (backup) {
   return new Promise((resolve, reject) => {
     backup.openDatabase(NOTES2_DB)
       .then(db => {
-        db.all(`SELECT ZICCLOUDSYNCINGOBJECT.*, ZICNOTEDATA.ZDATA as X_CONTENT_DATA, datetime(ZCREATIONDATE + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING FROM ZICCLOUDSYNCINGOBJECT LEFT JOIN ZICNOTEDATA ON ZICCLOUDSYNCINGOBJECT.ZNOTE = ZICNOTEDATA.ZNOTE`, async function (err, rows) {
+        db.all(`SELECT ZICCLOUDSYNCINGOBJECT.*, ZICNOTEDATA.ZDATA as X_CONTENT_DATA, ${apple_timestamp.parse('ZCREATIONDATE')} AS XFORMATTEDDATESTRING FROM ZICCLOUDSYNCINGOBJECT LEFT JOIN ZICNOTEDATA ON ZICCLOUDSYNCINGOBJECT.ZNOTE = ZICNOTEDATA.ZNOTE`, async function (err, rows) {
           if (err) reject(err)
 
           resolve(rows)
@@ -85,7 +86,7 @@ function getOldNotes (backup) {
   return new Promise((resolve, reject) => {
     backup.openDatabase(NOTES_DB)
       .then(db => {
-        db.all(`SELECT *, datetime(ZCREATIONDATE + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING from ZNOTE LEFT JOIN ZNOTEBODY ON ZBODY = ZNOTEBODY.Z_PK`, function (err, rows) {
+        db.all(`SELECT *, ${apple_timestamp.parse('ZCREATIONDATE')} AS XFORMATTEDDATESTRING from ZNOTE LEFT JOIN ZNOTEBODY ON ZBODY = ZNOTEBODY.Z_PK`, function (err, rows) {
           if (err) reject(err)
           resolve(rows)
         })
@@ -98,7 +99,7 @@ function getNewNotesiOS10iOS11 (backup) {
   return new Promise((resolve, reject) => {
     backup.openDatabase(NOTES2_DB)
       .then(db => {
-        db.all(`SELECT ZICCLOUDSYNCINGOBJECT.*, ZICNOTEDATA.ZDATA as X_CONTENT_DATA, datetime(ZCREATIONDATE + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING, datetime(ZCREATIONDATE1 + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING1 FROM ZICCLOUDSYNCINGOBJECT LEFT JOIN ZICNOTEDATA ON ZICCLOUDSYNCINGOBJECT.ZNOTE = ZICNOTEDATA.ZNOTE`, function (err, rows) {
+        db.all(`SELECT ZICCLOUDSYNCINGOBJECT.*, ZICNOTEDATA.ZDATA as X_CONTENT_DATA, ${apple_timestamp.parse('(ZCREATIONDATE')} AS XFORMATTEDDATESTRING, ${apple_timestamp.parse('ZCREATIONDATE1')} AS XFORMATTEDDATESTRING1 FROM ZICCLOUDSYNCINGOBJECT LEFT JOIN ZICNOTEDATA ON ZICCLOUDSYNCINGOBJECT.ZNOTE = ZICNOTEDATA.ZNOTE`, function (err, rows) {
           if (err) reject(err)
 
           resolve(rows)

+ 2 - 1
tools/reports/phone/calls.js

@@ -1,5 +1,6 @@
 const fileHash = require('../../util/backup_filehash')
 const log = require('../../util/log')
+const apple_timestamp = require('../../util/apple_timestamp')
 
 const CALLS_DB = '2b2b0084a1bc3a5ac8c27afdf14afb42c61a19ca'
 const CALLS2_DB = fileHash('Library/CallHistoryDB/CallHistory.storedata')
@@ -105,7 +106,7 @@ function getCallsListLater (backup) {
   return new Promise((resolve, reject) => {
     backup.openDatabase(CALLS2_DB)
       .then(db => {
-        db.all(`SELECT *, datetime(ZDATE + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING from ZCALLRECORD ORDER BY ZDATE ASC`, async function (err, rows) {
+        db.all(`SELECT *, ${apple_timestamp.parse('ZDATE')} AS XFORMATTEDDATESTRING from ZCALLRECORD ORDER BY ZDATE ASC`, async function (err, rows) {
           if (err) reject(err)
 
           resolve(rows)

+ 2 - 1
tools/reports/photos/locations.js

@@ -1,4 +1,5 @@
 const fileHash = require('../../util/backup_filehash')
+const apple_timestamp = require('../../util/apple_timestamp')
 
 const PHOTOS_DB = fileHash('Media/PhotoData/Photos.sqlite', 'CameraRollDomain')
 
@@ -31,7 +32,7 @@ function getPhotoLocationHistory (backup) {
           ZLATITUDE, 
           ZLONGITUDE,
           ZFILENAME,
-          datetime(ZDATECREATED + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING 
+          ${apple_timestamp.parse('ZDATECREATED')} AS XFORMATTEDDATESTRING 
           FROM ZGENERICASSET ORDER BY ZDATECREATED ASC`, function (err, rows) {
           if (err) reject(err)
 

+ 3 - 2
tools/reports/safari/open_tabs.js

@@ -1,4 +1,5 @@
 const fileHash = require('../../util/backup_filehash')
+const apple_timestamp = require('../../util/apple_timestamp')
 
 const TABS_DB = fileHash('Library/Safari/BrowserState.db', 'AppDomain-com.apple.mobilesafari')
 
@@ -17,7 +18,7 @@ module.exports = {
   output: {
     title: el => el.title,
     url: el => el.url,
-    lastViewedTime: el => (new Date((el.last_viewed_time + 978307200) * 1000).toDateString()) + ' ' + (new Date((el.last_viewed_time + 978307200) * 1000).toTimeString())
+    lastViewedTime: el => el.last_viewed
   }
 }
 
@@ -26,7 +27,7 @@ const openTabsReport = (backup) => {
     backup.openDatabase(TABS_DB)
       .then(db => {
         db.all(`
-          select * from tabs
+          select *, ${apple_timestamp.parse('last_viewed_time')} as last_viewed from tabs
           order by last_viewed_time DESC
           `, function (err, rows) {
           if (err) reject(err)

+ 2 - 1
tools/reports/safari/webhistory.js

@@ -1,5 +1,6 @@
 const { URL } = require('url')
 const fileHash = require('../../util/backup_filehash')
+const apple_timestamp = require('../../util/apple_timestamp')
 const HISTORY_DB = fileHash('Library/Safari/History.db', 'AppDomain-com.apple.mobilesafari')
 
 module.exports = {
@@ -27,7 +28,7 @@ function getWebHistory (backup) {
   return new Promise((resolve, reject) => {
     backup.openDatabase(HISTORY_DB)
       .then(db => {
-        db.all(`SELECT *, datetime(visit_time + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING from history_visits LEFT JOIN history_items ON history_items.ROWID = history_visits.history_item`, function (err, rows) {
+        db.all(`SELECT *, ${apple_timestamp.parse('visit_time')} AS XFORMATTEDDATESTRING from history_visits LEFT JOIN history_items ON history_items.ROWID = history_visits.history_item`, function (err, rows) {
           if (err) reject(err)
 
           resolve(rows)

+ 2 - 1
tools/reports/system/geofences.js

@@ -1,4 +1,5 @@
 const fileHash = require('../../util/backup_filehash')
+const apple_timestamp = require('../../util/apple_timestamp')
 
 const GEO_DB = fileHash('Library/Caches/locationd/consolidated.db', 'RootDomain')
 
@@ -26,7 +27,7 @@ function getGeoFences (backup) {
   return new Promise((resolve, reject) => {
     backup.openDatabase(GEO_DB)
       .then(db => {
-        db.all(`SELECT datetime(Timestamp + 978307200, 'unixepoch') AS XFORMATTEDDATESTRING, Latitude, Longitude, Distance FROM Fences ORDER BY Timestamp ASC`, async function (err, rows) {
+        db.all(`SELECT ${apple_timestamp.parse('Timestamp')} AS XFORMATTEDDATESTRING, Latitude, Longitude, Distance FROM Fences ORDER BY Timestamp ASC`, async function (err, rows) {
           if (err) reject(err)
 
           resolve(rows)

+ 8 - 0
tools/util/apple_timestamp.js

@@ -0,0 +1,8 @@
+
+module.exports = {
+  parse: (field_name) => {
+    return `CASE WHEN (${field_name} > 1000000000) THEN datetime(${field_name} / 1000000000 + 978307200, 'unixepoch') 
+                 WHEN ${field_name} <> 0 THEN datetime((${field_name} + 978307200), 'unixepoch') 
+                 ELSE ${field_name} END`
+  }
+}