Procházet zdrojové kódy

Address book report enhancements (#23)

* Address book add created date and modification date fields
* Address book add 'note' field
* Address book report enhancement: username and profile links for other services (google, icloud, generic service)
* Address book enhancement: include profile picture as base64 encoded string
* Address book enhancement: table report include 'picture' column with 1 or 0 value on profile picture existence
Alberto Güerere před 7 roky
rodič
revize
a00d2d834f
2 změnil soubory, kde provedl 55 přidání a 5 odebrání
  1. 4 1
      tools/reports/address_book.js
  2. 51 4
      tools/util/iphone_backup.js

+ 4 - 1
tools/reports/address_book.js

@@ -26,7 +26,10 @@ module.exports.func = function (program, backup, resolve, reject) {
           'Phone Work': el => el.phone_work ? el.phone_work.substring(0, 14) + '' : '',
           'Phone Mobile': el => el.phone_mobile ? el.phone_mobile.substring(0, 14) + '' : '',
           'Phone Home': el => el.phone_home ? el.phone_home.substring(0, 14) + '' : '',
-          'Email': el => el.email ? el.email.substring(0, 28) + '' : ''
+          'Email': el => el.email ? el.email.substring(0, 28) + '' : '',
+          'Created Date': el => el.created_date ? el.created_date.substring(0, 28) + '' : '',
+          'Note': el => el.note ? el.note.substring(0, 28) + '' : '',
+          'Picture': el => el.profile_picture ? 1 : 0
         }
       })
 

+ 51 - 4
tools/util/iphone_backup.js

@@ -25,6 +25,7 @@ const databases = {
   Notes: fileHash('Library/Notes/notes.sqlite'),
   Notes2: fileHash('NoteStore.sqlite', 'AppDomainGroup-group.com.apple.notes'),
   AddressBook: fileHash('Library/AddressBook/AddressBook.sqlitedb'),
+  AddressBookImages: fileHash('Library/AddressBook/AddressBookImages.sqlitedb'),
   'Cookies.binarycookies': '69b1865768101bacde5b77ccc44445cea9ce1261',
   Calls: '2b2b0084a1bc3a5ac8c27afdf14afb42c61a19ca',
   Calls2: fileHash('Library/CallHistoryDB/CallHistory.storedata'),
@@ -593,8 +594,10 @@ class IPhoneBackup {
 
   getAddressBook () {
     return new Promise((resolve, reject) => {
-      var addressbookdb = this.getDatabase(databases.AddressBook)
+      let addressbookdb = this.getDatabase(databases.AddressBook)
+      const self = this
       try {
+        // Query basic Address Book fields
         const query = `
         select ABPerson.ROWID
             , ABPerson.first
@@ -604,7 +607,8 @@ class IPhoneBackup {
             , ABPerson.Department as department
             , ABPerson.Birthday as birthday
             , ABPerson.JobTitle as jobtitle
-
+            , datetime(ABPerson.CreationDate + 978307200, 'unixepoch') as created_date 
+            , datetime(ABPerson.ModificationDate + 978307200, 'unixepoch') as updated_date 
             , (select value from ABMultiValue where property = 3 and record_id = ABPerson.ROWID and label = (select ROWID from ABMultiValueLabel where value = '_$!<Work>!$_')) as phone_work
             , (select value from ABMultiValue where property = 3 and record_id = ABPerson.ROWID and label = (select ROWID from ABMultiValueLabel where value = '_$!<Mobile>!$_')) as phone_mobile
             , (select value from ABMultiValue where property = 3 and record_id = ABPerson.ROWID and label = (select ROWID from ABMultiValueLabel where value = '_$!<Home>!$_')) as phone_home
@@ -613,13 +617,56 @@ class IPhoneBackup {
             
             , (select value from ABMultiValueEntry where parent_id in (select ROWID from ABMultiValue where record_id = ABPerson.ROWID) and key = (select ROWID from ABMultiValueEntryKey where lower(value) = 'street')) as address
             , (select value from ABMultiValueEntry where parent_id in (select ROWID from ABMultiValue where record_id = ABPerson.ROWID) and key = (select ROWID from ABMultiValueEntryKey where lower(value) = 'city')) as city
+            , ABPerson.Note as note
           from ABPerson
         order by ABPerson.ROWID
         `
         addressbookdb.all(query, async function (err, rows) {
           if (err) reject(err)
-
-          resolve(rows)
+          const iterateElements = (elements, index, callback) => {
+            if (index === elements.length) { return callback() }
+            // do parse call with element
+            let ele = elements[index]
+            //Query username and profile links for other services (facebook etc)
+            const query = `
+            select (select value from ABMultiValue where property = 22 and record_id = ABPerson.ROWID and label = (select ROWID from ABMultiValueLabel where value = 'PROFILE')) as google_profile
+                , (select value from ABMultiValue where property = 22 and record_id = ABPerson.ROWID and label = (select ROWID from ABMultiValueLabel where value = 'profile')) as google_profile1
+                , (select value from ABMultiValue where property = 4 and record_id = ABPerson.ROWID and label = (select ROWID from ABMultiValueLabel where value = 'iCloud')) as icloud
+                
+                , (select value from ABMultiValueEntry where parent_id in (select ROWID from ABMultiValue where record_id = ABPerson.ROWID) and key = (select ROWID from ABMultiValueEntryKey where lower(value) = 'service')) as service
+                , (select value from ABMultiValueEntry where parent_id in (select ROWID from ABMultiValue where record_id = ABPerson.ROWID) and key = (select ROWID from ABMultiValueEntryKey where lower(value) = 'username')) as username
+                , (select value from ABMultiValueEntry where parent_id in (select ROWID from ABMultiValue where record_id = ABPerson.ROWID) and key = (select ROWID from ABMultiValueEntryKey where lower(value) = 'url')) as url
+              from ABPerson
+              where ABPerson.ROWID = ${ele.ROWID}
+            order by ABPerson.ROWID
+            `
+            addressbookdb.all(query, async function (err, rows1) {
+              if (err) reject(err)
+              rows1[0].google_profile = rows1[0].google_profile || rows1[0].google_profile1
+              delete rows1[0].google_profile1
+              ele.services = rows1[0]
+              
+              const addressbookimagesdb = self.getDatabase(databases.AddressBookImages)
+              //Query profile picture extraction from /Library/AddressBook/AddressBookImages.sqlitedb
+              const query = `
+              select data
+              from ABFullSizeImage
+                where ABFullSizeImage.record_id = ${ele.ROWID}
+              `
+              addressbookimagesdb.get(query, async function (err, row) {
+                if (err) reject(err)
+                ele.profile_picture = null
+                if (row) {
+                  ele.profile_picture = row.data.toString('base64')
+                }
+                iterateElements(elements, index + 1, callback)
+              })
+              
+            })
+          }
+          iterateElements(rows, 0, () => {
+            resolve(rows)
+          })
         })
       } catch (e) {
         reject(e)