Selaa lähdekoodia

Update third party reporters to use API v4

Tanel Karindi 6 vuotta sitten
vanhempi
commit
6cc2fc296e

+ 40 - 77
tools/reports/thirdparty/facebook/messenger.js

@@ -5,27 +5,29 @@ const fileHash = require('../../../util/backup_filehash')
 
 const domain = 'AppDomainGroup-group.com.facebook.Messenger'
 
-module.exports.name = 'facebook_messenger_friends'
-module.exports.description = 'Show Facebook Messenger friends'
 
-// Specify this only works for iOS 9+
-module.exports.supportedVersions = '>=10.0'
 
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
+module.exports = {
+  version: 4,
+  name: 'facebook_messenger_friends',
+  description: `Show Facebook Messenger friends`,
+  requiresBackup: true,
 
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return facebookMessengerFriendsReport(backup)
+    },
 
-// You can also provide an array of functions instead of using `module.exports.func`.
-// These functions *should* be independent ranges to ensure reliable execution
-module.exports.functions = {
+  // Fields for apps report
+  output: {
+      'Facebook Friend Username': el => el.field_value
+  }
+}
 
-  '>=10.0': function (program, backup, resolve, reject) {
-    // This function would be called for iOS 10+
 
-    backup.getFileManifest()
+const facebookMessengerFriendsReport = (backup, file) => {
+  return new Promise((resolve, reject) => {
+    backup.getManifest()
       .then((items) => {
         let filename = 'fbomnistore.db'
         let fileitem = items.find((file) => {
@@ -35,68 +37,29 @@ module.exports.functions = {
         if (fileitem) {
           let filepath = fileitem.relativePath
           let file = fileHash(filepath, domain)
-          return facebookMessengerFriendsReport(backup, file)
-        } else return [] // Return an empty array to the formatter, since no fbomnistore.db file can be found in the manifest
-      })
-      .then((items) => {
-        var result = program.formatter.format(items, {
-          program: program,
-          columns: {
-            'Facebook Friend Usernames': el => el.field_value
-          }
-        })
-
-        resolve(result)
-      })
-      .catch((e) => {
-        log.error('[!] Encountered an Error:', e)
-      })
-  },
-
-  '>=5.0,<10.0': function (program, backup, resolve, reject) {
-    // This function would be called for all iOS 5 up to iOS 9.x.
-    // TODO
-    /* backup.getOldFileManifest()
-      .then((items) => {
-        var result = program.formatter.format(items, {
-          program: program,
-          columns: {
-            'Facebook Friend Username': el => el.field_value
-          }
-        })
-
-        resolve(result)
-      })
-      .catch(reject) */
-  }
-}
-
-const facebookMessengerFriendsReport = (backup, file) => {
-  return new Promise((resolve, reject) => {
-    var database = backup.getDatabase(file)
-    try {
-      database.get(`
-      SELECT name 
-      FROM sqlite_master 
-      WHERE type='table' 
-      AND name LIKE 'collection_index#messenger_contacts_ios%' 
-      LIMIT 1
-      `,
-      (err, tableName) => {
-        if (err) return reject(err)
-        tableName = tableName.name
-        log.verbose('Table', tableName)
-        database.all(`
-        SELECT field_value 
-        FROM '${tableName}' 
-        WHERE field_name='username'
-        `, (err, rows) => {
-          if (err) return reject(err)
-          resolve(rows)
-        })
+          backup.openDatabase(file).then(database => {
+              database.get(`
+                      SELECT name 
+                      FROM sqlite_master 
+                      WHERE type='table' 
+                      AND name LIKE 'collection_index#messenger_contacts_ios%' 
+                      LIMIT 1
+                      `,
+                     (err, tableName) => {
+                         if (err) return reject(err)
+                         tableName = tableName.name
+                         log.verbose('Table', tableName)
+                         database.all(`
+                            SELECT field_value 
+                            FROM '${tableName}' 
+                            WHERE field_name='username'
+                            `, (err, rows) => {
+                                if (err) return reject(err)
+                                resolve(rows)
+                            })
+                     })
+          }).catch(reject)
+        } else reject("Cannot find fbomnistore.db") // Return an empty array to the formatter, since no fbomnistore.db file can be found in the manifest
       })
-    } catch (e) {
-      reject(e)
-    }
   })
 }

+ 15 - 22
tools/reports/thirdparty/facebook/profile.js

@@ -6,29 +6,22 @@ const fileHash = require('../../../util/backup_filehash')
 
 const file = fileHash('Library/Preferences/com.facebook.Messenger.plist', 'AppDomain-com.facebook.Messenger')
 
-module.exports.name = 'facebook_profile'
-module.exports.description = 'Show Facebook Messenger user id'
-
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
-
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  facebookProfileReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
-          'Facebook User ID': el => el.fbid
-        }
-      })
 
-      resolve(result)
-    })
-    .catch(reject)
+module.exports = {
+  version: 4,
+  name: 'facebook_profile',
+  description: `Show Facebook Messenger user id`,
+  requiresBackup: true,
+
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return facebookProfileReport(backup)
+    },
+
+  // Fields for apps report
+  output: {
+          'Facebook User ID': el => el.fbid
+  }
 }
 
 const facebookProfileReport = (backup) => {

+ 14 - 19
tools/reports/thirdparty/gmail/accounts.js

@@ -6,33 +6,28 @@ const fileHash = require('../../../util/backup_filehash')
 
 const file = fileHash('Library/Preferences/group.com.google.Gmail.plist', 'AppDomainGroup-group.com.google.Gmail')
 
-module.exports.name = 'gmail_accounts'
-module.exports.description = 'Show Gmail account(s) information'
 
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
+module.exports = {
+  version: 4,
+  name: 'gmail_accounts',
+  description: `Show Gmail account(s) information`,
+  requiresBackup: true,
 
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return gmailAccountsReport(backup)
+    },
 
-module.exports.func = function (program, backup, resolve, reject) {
-  gmailAccountsReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+  // Fields for apps report
+  output: {
           'Id': el => el.id,
           'Email': el => el.email,
           'Avatar': el => el.avatar || null
-        }
-      })
-
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
+
+
 const gmailAccountsReport = (backup) => {
   return new Promise((resolve, reject) => {
     var filename = backup.getFileName(file)

+ 14 - 19
tools/reports/thirdparty/gmail/shared_contacts.js

@@ -6,34 +6,29 @@ const fileHash = require('../../../util/backup_filehash')
 
 const file = fileHash('Library/Preferences/group.com.google.Gmail.plist', 'AppDomainGroup-group.com.google.Gmail')
 
-module.exports.name = 'gmail_shared_contacts'
-module.exports.description = 'Show Gmail account(s) shared contacts information'
 
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
+module.exports = {
+  version: 4,
+  name: 'gmail_shared_contacts',
+  description: `Show Gmail account(s) shared contacts information`,
+  requiresBackup: true,
 
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return gmailAccountsReport(backup)
+    },
 
-module.exports.func = function (program, backup, resolve, reject) {
-  gmailAccountsReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+  // Fields for apps report
+  output: {
           'Account': el => el.account,
           'Name': el => el.name,
           'Email': el => el.email,
           'Avatar': el => el.avatar
-        }
-      })
-
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
+
+
 const gmailAccountsReport = (backup) => {
   return new Promise((resolve, reject) => {
     var filename = backup.getFileName(file)

+ 16 - 22
tools/reports/thirdparty/instagram/fb_friends.js

@@ -6,34 +6,28 @@ const fileHash = require('../../../util/backup_filehash')
 
 const file = fileHash('Library/Preferences/group.com.burbn.instagram.plist', 'AppDomainGroup-group.com.burbn.instagram')
 
-module.exports.name = 'instagram_fb_friends'
-module.exports.description = 'Show Instagram and Facebook friends data'
-
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
-
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  instagramRecentSearchesReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+
+module.exports = {
+  version: 4,
+  name: 'instagram_fb_friends',
+  description: `Show Instagram and Facebook friends data`,
+  requiresBackup: true,
+
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return instagramRecentSearchesReport(backup)
+    },
+
+  // Fields for apps report
+  output: {
           'Fb_id': el => el.fb_id,
           'Name': el => el.full_name,
           'Profile Pic': el => el.profile_pic_url,
           'Invited': el => el.is_invited
-        }
-      })
-
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
+
 const instagramRecentSearchesReport = (backup) => {
   return new Promise((resolve, reject) => {
     var results = []

+ 14 - 22
tools/reports/thirdparty/instagram/following_users_coded.js

@@ -6,29 +6,21 @@ const fileHash = require('../../../util/backup_filehash')
 
 const file = fileHash('Library/Preferences/group.com.burbn.instagram.plist', 'AppDomainGroup-group.com.burbn.instagram')
 
-module.exports.name = 'instagram_following_users_coded'
-module.exports.description = 'Show Instagram following users coded data'
-
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
-
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  instagramRecentSearchesReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+module.exports = {
+  version: 4,
+  name: 'instagram_following_users_coded',
+  description: `Show Instagram following users coded data`,
+  requiresBackup: true,
+
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return instagramRecentSearchesReport(backup)
+    },
+
+  // Fields for apps report
+  output: {
           'Identifier': el => el
-        }
-      })
-
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
 const instagramRecentSearchesReport = (backup) => {

+ 15 - 22
tools/reports/thirdparty/instagram/profile.js

@@ -6,32 +6,25 @@ const fileHash = require('../../../util/backup_filehash')
 
 const file = fileHash('Library/Preferences/com.burbn.instagram.plist', 'AppDomain-com.burbn.instagram')
 
-module.exports.name = 'instagram_profile'
-module.exports.description = 'Show Instagram profile/user data'
-
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
-
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  instagramProfileReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+module.exports = {
+  version: 4,
+  name: 'instagram_profile',
+  description: `Show Instagram profile/user data`,
+  requiresBackup: true,
+
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return instagramProfileReport(backup)
+    },
+
+  // Fields for apps report
+  output: {
           'Key': el => el.key,
           'Value': el => el.value
-        }
-      })
-
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
+
 function KeyValue (property, plist) {
   this.key = property
   this.value = plist[property] ? plist[property] : 'N/A'

+ 16 - 22
tools/reports/thirdparty/instagram/recent_searches.js

@@ -6,32 +6,26 @@ const fileHash = require('../../../util/backup_filehash')
 
 const file = fileHash('Library/Preferences/group.com.burbn.instagram.plist', 'AppDomainGroup-group.com.burbn.instagram')
 
-module.exports.name = 'instagram_recent_searches'
-module.exports.description = 'Show Instagram recent searches coded data'
-
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
-
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  instagramRecentSearchesReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+
+module.exports = {
+  version: 4,
+  name: 'instagram_recent_searches',
+  description: `Show Instagram recent searches coded data`,
+  requiresBackup: true,
+
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return instagramRecentSearchesReport(backup)
+    },
+
+  // Fields for apps report
+  output: {
           'Type': el => el.type,
           'Identifier': el => el.identifier
-        }
-      })
-
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
+
 const instagramRecentSearchesReport = (backup) => {
   return new Promise((resolve, reject) => {
     var results = []

+ 38 - 52
tools/reports/thirdparty/skype/accounts.js

@@ -3,61 +3,47 @@ const fileHash = require('../../../util/backup_filehash')
 
 const domain = 'AppDomain-com.skype.skype'
 
-module.exports.name = 'skype_accounts'
-module.exports.description = 'Show Skype accounts'
+module.exports = {
+  version: 4,
+  name: 'skype.accounts',
+  description: `Show Skype accounts`,
+  requiresBackup: true,
 
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return skypeAccountsReport(backup)
+    },
 
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  backup.getFileManifest()
-    .then((items) => {
-      let filename = 'main.db'
-      let fileitem = items.find((file) => {
-        if (file && file.relativePath) {
-          return ~file.relativePath.indexOf(filename) && file.domain === domain
-        }
-        return false
-      })
-      if (fileitem) {
-        let filepath = fileitem.relativePath
-        let file = fileHash(filepath, domain)
-        return skypeAccountsReport(backup, file)
-      } else return [] // Return an empty array to the formatter, since no main.db file can be found in the manifest
-    })
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+  // Fields for apps report
+  output: {
           'Skype Name': el => el.skypename
-        }
-      })
-
-      resolve(result)
-    })
-    .catch((e) => {
-      console.log('[!] Encountered an Error:', e)
-    })
+  }
 }
 
-const skypeAccountsReport = (backup, file) => {
-  return new Promise((resolve, reject) => {
-    var database = backup.getDatabase(file)
-    try {
-      database.all(`
-      SELECT * 
-      FROM Accounts 
-      `,
-      (err, rows) => {
-        if (err) resolve(err)
-        resolve(rows)
-      })
-    } catch (e) {
-      reject(e)
-    }
-  })
+
+const skypeAccountsReport = (backup) => { 
+    return new Promise((resolve, reject) => {
+        backup.getManifest()
+            .then((items) => {
+                let filename = 'main.db'
+                let fileitem = items.find((file) => {
+                    if (file && file.relativePath) {
+                        return ~file.relativePath.indexOf(filename) && file.domain === domain
+                    }
+                    return false
+                })
+                
+                if (fileitem) {
+                    let filepath = fileitem.relativePath
+                    let file = fileHash(filepath, domain)
+                    
+                    backup.openDatabase(file).then(database => {
+                        database.all(`SELECT * FROM Accounts `, (err, rows) => {
+                            if (err) resolve(err)
+                            resolve(rows);
+                        })
+                    }).catch(reject)
+                } else reject("Cannot find main.db"); // Return an empty array to the formatter, since no main.db file can be found in the manifest
+            });
+    })
 }

+ 34 - 48
tools/reports/thirdparty/skype/calls.js

@@ -3,65 +3,51 @@ const fileHash = require('../../../util/backup_filehash')
 
 const domain = 'AppDomain-com.skype.skype'
 
-module.exports.name = 'skype_calls'
-module.exports.description = 'Show Skype calls'
 
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
+module.exports = {
+  version: 4,
+  name: 'skype_calls',
+  description: `Show Skype calls`,
+  requiresBackup: true,
 
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return skypeAccountsReport(backup)
+    },
 
-module.exports.func = function (program, backup, resolve, reject) {
-  backup.getFileManifest()
-    .then((items) => {
-      let filename = 'main.db'
-      let fileitem = items.find((file) => {
-        if (file && file.relativePath) {
-          return ~file.relativePath.indexOf(filename) && file.domain === domain
-        }
-        return false
-      })
-      if (fileitem) {
-        let filepath = fileitem.relativePath
-        let file = fileHash(filepath, domain)
-        return skypeAccountsReport(backup, file)
-      } else return [] // Return an empty array to the formatter, since no main.db file can be found in the manifest
-    })
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+  // Fields for apps report
+  output: {
           'Begin Timestamp': el => (new Date((el.begin_timestamp) * 1000).toDateString()) + ' ' + (new Date((el.begin_timestamp) * 1000).toTimeString()),
           'Host Identity': el => el.host_identity,
           'Duration': el => el.duration ? el.duration : 'N/A',
           'Is Incoming': el => el.is_incoming === 1 ? 'Yes' : 'No',
           'Caller': el => el.caller_mri_identity
-        }
-      })
-
-      resolve(result)
-    })
-    .catch((e) => {
-      console.log('[!] Encountered an Error:', e)
-    })
+  }
 }
 
+
 const skypeAccountsReport = (backup, file) => {
   return new Promise((resolve, reject) => {
-    var database = backup.getDatabase(file)
-    try {
-      database.all(`
-      SELECT * 
-      FROM Calls 
-      `,
-      (err, rows) => {
-        if (err) return reject(err)
-        resolve(rows)
-      })
-    } catch (e) {
-      reject(e)
-    }
+      backup.getManifest()
+          .then((items) => {
+              let filename = 'main.db'
+              let fileitem = items.find((file) => {
+                  if (file && file.filename) {
+                      return ~file.filename.indexOf(filename) && file.domain === domain
+                  }
+                  return false
+              })
+              if (fileitem) {
+                  let filepath = fileitem.filename
+                  let file = fileHash(filepath, domain)
+                  backup.openDatabase(file).then(database => {
+                  database.all(` SELECT * FROM Calls `,
+                               (err, rows) => {
+                                   if (err) return reject(err)
+                                   resolve(rows)
+                               })
+                  }).catch(reject)
+              } else reject("Cannot find main.db") // Return an empty array to the formatter, since no main.db file can be found in the manifest
+    })
   })
 }

+ 16 - 22
tools/reports/thirdparty/spotify/searches.js

@@ -6,31 +6,25 @@ const fileHash = require('../../../util/backup_filehash')
 
 const database = fileHash('Library/Preferences/com.spotify.client.plist', 'AppDomain-com.spotify.client')
 
-module.exports.name = 'spotify.searches'
-module.exports.description = 'List associated Spotify account and its usage information'
-
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
-
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  spotifyReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+
+module.exports = {
+  version: 4,
+  name: 'spotify.searches',
+  description: `List associated Spotify account and its usage information`,
+  requiresBackup: true,
+
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return spotifyReport(backup)
+    },
+
+  // Fields for apps report
+  output: {
           'Username': el => el.username,
           'Type': el => el.placeholderIconIdentifier ? el.placeholderIconIdentifier.toLowerCase() : 'song',
           'Title': el => el.title,
           'Subtitle': el => el.subtitle
-        }
-      })
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
 const spotifyReport = (backup) => {
@@ -40,7 +34,7 @@ const spotifyReport = (backup) => {
       let spotifyData = bplist.parseBuffer(fs.readFileSync(filename))[0]
       let spotifyResult = []
 
-      // console.log('spotifyData', spotifyData)
+      console.log('spotifyData', spotifyData)
       // Get spotify username
       if (Object.keys(spotifyData).some((key) => ~key.indexOf('.com.spotify'))) {
         const keys = Object.keys(spotifyData).filter((key) => ~key.indexOf('.com.spotify'))

+ 27 - 35
tools/reports/thirdparty/viber/calls.js

@@ -1,53 +1,45 @@
 // Derive filenames based on domain + file path
 const fileHash = require('../../../util/backup_filehash')
+const apple_timestamp = require('../../../util/apple_timestamp')
 
 const database = fileHash('com.viber/database/Contacts.data', 'AppDomainGroup-group.viber.share.container')
 
-module.exports.name = 'viber_calls'
-module.exports.description = 'List Viber calls'
+module.exports = {
+  version: 4,
+  name: 'viber_calls',
+  description: `List Viber calls`,
+  requiresBackup: true,
 
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return viberCallsReport(backup)
+    },
 
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  viberCallsReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+  // Fields for apps report
+  output: {
           'PK': el => el.Z_PK,
-          'Date': el => (new Date((el.ZDATE + 978307200) * 1000).toDateString()) + ' ' + (new Date((el.ZDATE + 978307200) * 1000).toTimeString()),
+          'Date': el => el.ZDATE_STRING,
           'Name': el => el.ZMAINNAME + ' ' + el.ZSUFFIXNAME,
           'Phone': el => el.ZPHONENUMBER,
           'Call Type': el => el.ZCALLTYPE
-        }
-      })
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
+
 const viberCallsReport = (backup) => {
-  return new Promise((resolve, reject) => {
-    var vibercallsdb = backup.getDatabase(database)
-    try {
-      const query = `
-        SELECT * FROM ZRECENTSLINE
+    return new Promise((resolve, reject) => {
+        backup.openDatabase(database).then(database => {
+            const query = `
+        SELECT *, ${apple_timestamp.parse('ZRECENTSLINE.ZDATE')} AS ZDATE_STRING FROM ZRECENTSLINE
         INNER JOIN ZABCONTACT
         ON ZABCONTACT.Z_PK = ZRECENTSLINE.ZCONTACT
         ORDER BY ZABCONTACT.Z_PK;
-        `
-      vibercallsdb.all(query, async function (err, rows) {
-        if (err) reject(err)
-
-        resolve(rows)
-      })
-    } catch (e) {
-      reject(e)
-    }
-  })
+        `            
+            database.all(query, (err, rows) => {
+                if (err) resolve(err)
+                resolve(rows);
+            })
+        }).catch(reject)
+        
+    })
 }

+ 20 - 30
tools/reports/thirdparty/viber/contacts.js

@@ -3,49 +3,39 @@ const fileHash = require('../../../util/backup_filehash')
 
 const database = fileHash('com.viber/database/Contacts.data', 'AppDomainGroup-group.viber.share.container')
 
-module.exports.name = 'viber_contacts'
-module.exports.description = 'List Viber contacts'
+module.exports = {
+  version: 4,
+  name: 'viber_contacts',
+  description: `List Viber contacts`,
+  requiresBackup: true,
 
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return viberContactsReport(backup)
+    },
 
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  viberContactsReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+  // Fields for apps report
+  output: {
           'PK': el => el.Z_PK,
           'Name': el => el.ZDISPLAYFULLNAME,
           'Phone': el => el.ZPHONE
-        }
-      })
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
+
 const viberContactsReport = (backup) => {
   return new Promise((resolve, reject) => {
-    var vibercontactsdb = backup.getDatabase(database)
-    try {
-      const query = `
+      backup.openDatabase(database).then(database => {
+            const query = `
         SELECT * FROM ZMEMBER
         INNER JOIN ZPHONENUMBER
         ON ZPHONENUMBER.ZMEMBER = ZMEMBER.Z_PK
         ORDER BY ZMEMBER.Z_PK;
         `
-      vibercontactsdb.all(query, async function (err, rows) {
-        if (err) reject(err)
-
-        resolve(rows)
-      })
-    } catch (e) {
-      reject(e)
-    }
+          database.all(query, async function (err, rows) {
+              if (err) reject(err)
+              resolve(rows)
+          })
+      }).catch(reject)
   })
 }

+ 21 - 29
tools/reports/thirdparty/viber/messages.js

@@ -1,55 +1,47 @@
 // Derive filenames based on domain + file path
 const fileHash = require('../../../util/backup_filehash')
+const apple_timestamp = require('../../../util/apple_timestamp')
 
 const database = fileHash('com.viber/database/Contacts.data', 'AppDomainGroup-group.viber.share.container')
 
-module.exports.name = 'viber_messages'
-module.exports.description = 'List Viber messages'
 
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
+module.exports = {
+  version: 4,
+  name: 'viber_messages',
+  description: `List Viber messages`,
+  requiresBackup: true,
 
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return viberMessagesReport(backup)
+    },
 
-module.exports.func = function (program, backup, resolve, reject) {
-  viberMessagesReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+  // Fields for apps report
+  output: {
           'PK': el => el.Z_PK,
-          'Date': el => (new Date((el.ZDATE + 978307200) * 1000).toDateString()) + ' ' + (new Date((el.ZDATE + 978307200) * 1000).toTimeString()),
+          'Date': el => ZDATE_STRING,
           'Name': el => el.ZDISPLAYFULLNAME,
           'Text': el => el.ZTEXT,
           'State': el => el.ZSTATE
-        }
-      })
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
 const viberMessagesReport = (backup) => {
-  return new Promise((resolve, reject) => {
-    var vibermessagesdb = backup.getDatabase(database)
-    try {
-      const query = `
-        SELECT * FROM ZVIBERMESSAGE
+    return new Promise((resolve, reject) => {
+        console.log(database)
+     backup.openDatabase(database).then(database => {
+            const query = `
+        SELECT *, ${apple_timestamp.parse('ZVIBERMESSAGE.ZDATE')} AS ZDATE_STRING FROM ZVIBERMESSAGE
         INNER JOIN ZCONVERSATION
         ON ZCONVERSATION.Z_PK = ZVIBERMESSAGE.ZCONVERSATION
         INNER JOIN ZMEMBER
         ON ZCONVERSATION.ZINTERLOCUTOR = ZMEMBER.Z_PK
         ORDER BY ZVIBERMESSAGE.Z_PK DESC;
         `
-      vibermessagesdb.all(query, async function (err, rows) {
+      database.all(query, async function (err, rows) {
         if (err) reject(err)
-
         resolve(rows)
       })
-    } catch (e) {
-      reject(e)
-    }
+     }).catch(reject)
   })
 }

+ 25 - 36
tools/reports/thirdparty/waze/favorites.js

@@ -10,22 +10,19 @@ const fileHash = require('../../../util/backup_filehash')
 
 const database = fileHash('Documents/user.db', 'AppDomain-com.waze.iphone')
 
-module.exports.name = 'waze_favorites'
-module.exports.description = 'List Waze app favorite places'
-
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
-
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  wazeReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+module.exports = {
+  version: 4,
+  name: 'waze_favorites',
+  description: `List Waze app favorite places`,
+  requiresBackup: true,
+
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return wazeReport(backup)
+    },
+
+  // Fields for apps report
+  output: {
           'Name': el => el.name,
           'Modified Date': el => (new Date((el.modified_time) * 1000).toDateString()) + ' ' + (new Date((el.modified_time) * 1000).toTimeString()) ,
           'Latitude': el => el.latitude / 1000000,
@@ -34,11 +31,7 @@ module.exports.func = function (program, backup, resolve, reject) {
           'City': el => el.city,
           'State': el => el.state,
           'Country': el => el.country
-        }
-      })
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
 function KeyValue (property, plist) {
@@ -47,21 +40,17 @@ function KeyValue (property, plist) {
 }
 
 const wazeReport = (backup) => {
-  return new Promise((resolve, reject) => {
-    var wazedb = backup.getDatabase(database)
-      try {
+    return new Promise((resolve, reject) => {
         const query = `
         select FAVORITES.name, FAVORITES.created_time, FAVORITES.modified_time, FAVORITES.rank, PLACES.latitude, PLACES.longitude, PLACES.street, PLACES.city, PLACES.state, PLACES.country from FAVORITES
         left join PLACES on FAVORITES.place_id = PLACES.id
-        order by rank
-        `
-        wazedb.all(query, async function (err, rows) {
-          if (err) reject(err)
-
-          resolve(rows)
-        })
-      } catch (e) {
-        reject(e)
-      }
-  })
-}
+        order by rank  `
+        
+        backup.openDatabase(database).then(database => {
+            database.all(query, (err, rows) => {
+                if (err) resolve(err)
+                resolve(rows);
+            })
+        }).catch(reject)
+    })
+}

+ 20 - 25
tools/reports/thirdparty/waze/places.js

@@ -5,27 +5,26 @@ const bplist = require('bplist-parser')
 const fs = require('fs')
 const plist = require('plist')
 
+
 // Derive filenames based on domain + file path
 const fileHash = require('../../../util/backup_filehash')
 
 const database = fileHash('Documents/user.db', 'AppDomain-com.waze.iphone')
 
-module.exports.name = 'waze_places'
-module.exports.description = 'List Waze app places'
 
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
+module.exports = {
+  version: 4,
+  name: 'waze_places',
+  description: `List Waze app places`,
+  requiresBackup: true,
 
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return wazeReport(backup)
+    },
 
-module.exports.func = function (program, backup, resolve, reject) {
-  wazeReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+  // Fields for apps report
+  output: {
           'Name': el => el.name,
           'Created Date': el => (new Date((el.created_time) * 1000).toDateString()) + ' ' + (new Date((el.created_time) * 1000).toTimeString()) ,
           'Latitude': el => el.latitude / 1000000,
@@ -34,13 +33,11 @@ module.exports.func = function (program, backup, resolve, reject) {
           'City': el => el.city,
           'State': el => el.state,
           'Country': el => el.country
-        }
-      })
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
+
+
 function KeyValue (property, plist) {
   this.key = property
   this.value = plist[property] ? plist[property] : 'N/A'
@@ -48,19 +45,17 @@ function KeyValue (property, plist) {
 
 const wazeReport = (backup) => {
   return new Promise((resolve, reject) => {
-    var wazedb = backup.getDatabase(database)
-      try {
+    backup.openDatabase(database)
+    .then(db => {
         const query = `
         select * from PLACES
         order by id
         `
-        wazedb.all(query, async function (err, rows) {
+        db.all(query, async function (err, rows) {
           if (err) reject(err)
 
           resolve(rows)
         })
-      } catch (e) {
-        reject(e)
-      }
+    }).catch(reject)
   })
-}
+}

+ 24 - 33
tools/reports/thirdparty/waze/recents.js

@@ -10,22 +10,19 @@ const fileHash = require('../../../util/backup_filehash')
 
 const database = fileHash('Documents/user.db', 'AppDomain-com.waze.iphone')
 
-module.exports.name = 'waze_recents'
-module.exports.description = 'List Waze app recent destinations'
-
-// Specify this reporter requires a backup.
-// The second parameter to func() is now a backup instead of the path to one.
-module.exports.requiresBackup = true
-
-// Specify this reporter supports the promises API for allowing chaining of reports.
-module.exports.usesPromises = true
-
-module.exports.func = function (program, backup, resolve, reject) {
-  wazeReport(backup)
-    .then((items) => {
-      var result = program.formatter.format(items, {
-        program: program,
-        columns: {
+module.exports = {
+  version: 4,
+  name: 'waze_recents',
+  description: `List Waze app recent destinations`,
+  requiresBackup: true,
+
+  // Run on a v3 lib / backup object.
+    run (lib, { backup }) {
+        return wazeReport(backup)
+    },
+
+  // Fields for apps report
+  output: {
           'Id': el => el.id,
           'Name': el => el.name,
           'Created Date': el => (new Date((el.created_time) * 1000).toDateString()) + ' ' + (new Date((el.created_time) * 1000).toTimeString()) ,
@@ -36,13 +33,10 @@ module.exports.func = function (program, backup, resolve, reject) {
           'City': el => el.city,
           'State': el => el.state,
           'Country': el => el.country
-        }
-      })
-      resolve(result)
-    })
-    .catch(reject)
+  }
 }
 
+
 function KeyValue (property, plist) {
   this.key = property
   this.value = plist[property] ? plist[property] : 'N/A'
@@ -50,20 +44,17 @@ function KeyValue (property, plist) {
 
 const wazeReport = (backup) => {
   return new Promise((resolve, reject) => {
-    var wazedb = backup.getDatabase(database)
-      try {
-        const query = `
+      backup.openDatabase(database).then(database => {
+          const query = `
         select RECENTS.name, RECENTS.created_time, RECENTS.access_time, RECENTS.id, PLACES.latitude, PLACES.longitude, PLACES.street, PLACES.city, PLACES.state, PLACES.country from RECENTS
         left join PLACES on RECENTS.place_id = PLACES.id
         order by RECENTS.id
         `
-        wazedb.all(query, async function (err, rows) {
-          if (err) reject(err)
-
-          resolve(rows)
-        })
-      } catch (e) {
-        reject(e)
-      }
+          database.all(query, async function (err, rows) {
+              if (err) reject(err)
+              
+              resolve(rows)
+          })
+      }).catch(reject)
   })
-}
+}