Procházet zdrojové kódy

Add helper functions for parsing plist files and buffers

Centralizes the logic for detecting whether a plist is
binary or not.

This fixes a bunch of call sites that didn't account for
non-binary plist.
Tor Arne Vestbø před 5 roky
rodič
revize
ef5ff4c490

+ 2 - 2
tools/reports/backup/files.js

@@ -2,7 +2,7 @@ const fs = require('fs-extra')
 const path = require('path')
 const log = require('../../util/log')
 const manifestMBDBParse = require('../../util/manifest_mbdb_parse')
-const bplist = require('bplist-parser')
+const plist = require('../../util/plist')
 const Mode = require('stat-mode');
 
 module.exports = {
@@ -47,7 +47,7 @@ function getSqliteFileManifest (backup) {
 
           // Extract binary plist metadata
           for (var row of rows) {
-            let data = bplist.parseBuffer(row.file)[0]
+            let data = plist.parseBuffer(row.file)
             let metadata = data['$objects'][1];
             row.filelen = metadata.Size
             row.mode = metadata.Mode

+ 5 - 23
tools/reports/backup/info.js

@@ -1,9 +1,8 @@
 const fs = require('fs')
 const path = require('path')
-const plist = require('plist')
-const bplist = require('bplist-parser')
 
 const log = require('../../util/log')
+const plist = require('../../util/plist')
 
 module.exports = {
   version: 4,
@@ -16,28 +15,11 @@ module.exports = {
     // Get the path for the info plist.
     let infoPath = path.join(backup.path, 'Info.plist')
 
-    let fd = fs.openSync(infoPath, 'r')
-    let buffer = Buffer.alloc(7)
-    // Read the first 7 bytes into the buffer.
-    fs.readSync(fd, buffer, 0, 7, 0)
-    fs.closeSync(fd)
+    log.verbose('parsing info', infoPath)
+    var data = plist.parseFile(infoPath)
 
-    var data
-    // Binary plists have the marker 'bplist0'
-    if (buffer.toString('ascii') === 'bplist0') {
-      // Parse as binary plist
-      log.verbose('parsing manifest', infoPath)
-      data = bplist.parseBuffer(fs.readFileSync(infoPath))[0]
-
-      // Remove this data, it's kind of useless.
-      delete data['iTunes Files']
-    } else {
-      // Parse as normal plist.
-      log.verbose('parsing info', infoPath)
-      data = plist.parse(fs.readFileSync(infoPath, 'utf8'))
-
-      delete data['iTunes Files']
-    }
+    // Remove this data, it's kind of useless.
+    delete data['iTunes Files']
 
     return data
   },

+ 2 - 2
tools/reports/backup/manifest.js

@@ -2,7 +2,7 @@ const fs = require('fs')
 const path = require('path')
 
 const log = require('../../util/log')
-const bplist = require('bplist-parser')
+const plist = require('../../util/plist')
 
 module.exports = {
   version: 4,
@@ -14,7 +14,7 @@ module.exports = {
   async run (lib, { backup }) {
     // Load and parse the maniest for the backup.
     log.verbose('parsing manifest', backup.path)
-    let data = bplist.parseBuffer(fs.readFileSync(path.join(backup.path, 'Manifest.plist')))[0]
+    let data = plist.parseFile(path.join(backup.path, 'Manifest.plist'))
 
     // Remove this data, it's kind of useless.
     delete data['BackupKeyBag']

+ 2 - 4
tools/reports/backup/status.js

@@ -2,7 +2,7 @@ const fs = require('fs')
 const path = require('path')
 
 const log = require('../../util/log')
-const bplist = require('bplist-parser')
+const plist = require('../../util/plist')
 
 module.exports = {
   version: 4,
@@ -14,9 +14,7 @@ module.exports = {
   async run (lib, { backup }) {
     // Load and parse status for the backup.
     log.verbose('parsing status', backup.path)
-    let data = bplist.parseBuffer(fs.readFileSync(path.join(backup.path, 'Status.plist')))[0]
-
-    return data
+    return plist.parseFile(path.join(backup.path, 'Status.plist'))
   },
 
   // Status fields.

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

@@ -1,4 +1,4 @@
-const bplist = require('bplist-parser')
+const plist = require('../../util/plist')
 
 const fileHash = require('../../util/backup_filehash')
 const log = require('../../util/log')
@@ -39,7 +39,7 @@ function getConversationsiOS9 (backup) {
           // The timestamp information is stored in a binary blob named `properties`
           // Which is formatted as a binary PLIST.
           for (var el of rows) {
-            if (el.properties) el.properties = bplist.parseBuffer(el.properties)[0]
+            if (el.properties) el.properties = plist.parseBuffer(el.properties)
 
             // Interestingly, some of these do not have dates attached.
             if (el.properties) {

+ 2 - 2
tools/reports/phone/speed_dial.js

@@ -1,5 +1,5 @@
 
-const bplist = require('bplist-parser')
+const plist = require('../../util/plist')
 const fs = require('fs')
 
 // Derive filenames based on domain + file path
@@ -41,7 +41,7 @@ const speedDialReport = (backup) => {
   return new Promise((resolve, reject) => {
     try {
       var filename = backup.getFileName(file)
-      let speeddialPlist = bplist.parseBuffer(fs.readFileSync(filename))[0]
+      let speeddialPlist = plist.parseFile(filename)
 
       resolve(speeddialPlist)
     } catch (e) {

+ 2 - 2
tools/reports/safari/recent_searches.js

@@ -1,5 +1,5 @@
 const fs = require('fs')
-const bplist = require('bplist-parser')
+const plist = require('../../util/plist')
 const fileHash = require('../../util/backup_filehash')
 
 const SAFARI_PLIST = fileHash('Library/Preferences/com.apple.mobilesafari.plist', 'AppDomain-com.apple.mobilesafari')
@@ -28,7 +28,7 @@ const safariRecentSearches = (backup) => {
     try {
       // Get the filename of the ID
       var filename = backup.getFileName(SAFARI_PLIST)
-      let mobilesafariPlist = bplist.parseBuffer(fs.readFileSync(filename))[0]
+      let mobilesafariPlist = plist.parseFile(filename)
 
       resolve(mobilesafariPlist['RecentWebSearches'])
     } catch (e) {

+ 3 - 3
tools/reports/system/pushstore.js

@@ -1,5 +1,5 @@
 const fs = require('fs')
-const bplist = require('bplist-parser')
+const plist = require('../../util/plist')
 const pushstoreParse = require('../../util/pushstore_parse')
 
 module.exports = {
@@ -36,8 +36,8 @@ module.exports = {
 
         // For each file, run a parse on the plist.
         files.forEach((file) => {
-          let plist = bplist.parseBuffer(fs.readFileSync(backup.getFileName(file.id)))[0]
-          pushstores.push(...pushstoreParse.run(plist))
+          let data = plist.parseFile(backup.getFileName(file.id))
+          pushstores.push(...pushstoreParse.run(data))
         })
 
         resolve(pushstores)

+ 2 - 2
tools/reports/system/wifi.js

@@ -1,4 +1,4 @@
-const bplist = require('bplist-parser')
+const plist = require('../../util/plist')
 const fs = require('fs')
 
 // Normalize mac addresses in wifi output
@@ -23,7 +23,7 @@ module.exports = {
         var filename = backup.getFileName(WIFI_PLIST)
 
         // Attempt to parse it
-        let wifiList = bplist.parseBuffer(fs.readFileSync(filename))[0]
+        let wifiList = plist.parseFile(filename)
         let result = wifiList['List of known networks']
           .map(el => {
             if (el.BSSID) {

+ 2 - 2
tools/reports/thirdparty/facebook/profile.js

@@ -1,4 +1,4 @@
-const bplist = require('bplist-parser')
+const plist = require('../../../util/plist')
 const fs = require('fs')
 
 // Derive filenames based on domain + file path
@@ -28,7 +28,7 @@ const facebookProfileReport = (backup) => {
   return new Promise((resolve, reject) => {
     var filename = backup.getFileName(file)
     try {
-      let facebookPlist = bplist.parseBuffer(fs.readFileSync(filename))[0]
+      let facebookPlist = plist.parseFile(filename)
       let facebookUserIds = Object.keys(facebookPlist['kUserGlobalSettings'])
       facebookUserIds = facebookUserIds.map((fbid) => ({
         fbid: fbid

+ 2 - 2
tools/reports/thirdparty/gmail/accounts.js

@@ -1,4 +1,4 @@
-const bplist = require('bplist-parser')
+const plist = require('../../../util/plist')
 const fs = require('fs')
 
 // Derive filenames based on domain + file path
@@ -32,7 +32,7 @@ const gmailAccountsReport = (backup) => {
   return new Promise((resolve, reject) => {
     var filename = backup.getFileName(file)
     try {
-      let gmailPlist = bplist.parseBuffer(fs.readFileSync(filename))[0]
+      let gmailPlist = plist.parseFile(filename)
       let gmailAccountIds = Object.keys(gmailPlist).filter(key => key.indexOf('kIdToEmailMapKey') !== -1)
       let gmailAvatars = Object.keys(gmailPlist).filter(key => key.indexOf('kCurrentAvatarUrlKey') !== -1)
       gmailAvatars = gmailAvatars.map(avatarKey => {

+ 2 - 2
tools/reports/thirdparty/gmail/shared_contacts.js

@@ -1,4 +1,4 @@
-const bplist = require('bplist-parser')
+const plist = require('../../../util/plist')
 const fs = require('fs')
 
 // Derive filenames based on domain + file path
@@ -33,7 +33,7 @@ const gmailAccountsReport = (backup) => {
   return new Promise((resolve, reject) => {
     var filename = backup.getFileName(file)
     try {
-      let gmailPlist = bplist.parseBuffer(fs.readFileSync(filename))[0]
+      let gmailPlist = plist.parseFile(filename)
       let gmailAccountIds = Object.keys(gmailPlist).filter(key => key.indexOf('kIdToEmailMapKey') !== -1)
       let gmailContactsByAccount = Object.keys(gmailPlist).filter(key => key.indexOf('kInboxSharedStorageContacts') !== -1)
       gmailContactsByAccount = gmailContactsByAccount.map(contactsKey => {

+ 2 - 2
tools/reports/thirdparty/instagram/fb_friends.js

@@ -1,4 +1,4 @@
-const bplist = require('bplist-parser')
+const plist = require('../../../util/plist')
 const fs = require('fs')
 
 // Derive filenames based on domain + file path
@@ -33,7 +33,7 @@ const instagramRecentSearchesReport = (backup) => {
     var results = []
     var filename = backup.getFileName(file)
     try {
-      let instagramPlist = bplist.parseBuffer(fs.readFileSync(filename))[0]
+      let instagramPlist = plist.parseFile(filename)
       let regex = /[0-9]*-fb-friends$/g
       let fbFriendsKey = Object.keys(instagramPlist).filter(key => regex.test(key))
       console.log(fbFriendsKey)

+ 2 - 2
tools/reports/thirdparty/instagram/following_users_coded.js

@@ -1,4 +1,4 @@
-const bplist = require('bplist-parser')
+const plist = require('../../../util/plist')
 const fs = require('fs')
 
 // Derive filenames based on domain + file path
@@ -28,7 +28,7 @@ const instagramRecentSearchesReport = (backup) => {
     var results = []
     var filename = backup.getFileName(file)
     try {
-      let instagramPlist = bplist.parseBuffer(fs.readFileSync(filename))[0]
+      let instagramPlist = plist.parseFile(filename)
       let followingUsersKey = Object.keys(instagramPlist).filter(key => key.indexOf('-following-users.coded') !== -1)
       followingUsersKey.forEach(key => {
         let followingUsers = instagramPlist[key]

+ 2 - 2
tools/reports/thirdparty/instagram/profile.js

@@ -1,4 +1,4 @@
-const bplist = require('bplist-parser')
+const plist = require('../../../util/plist')
 const fs = require('fs')
 
 // Derive filenames based on domain + file path
@@ -35,7 +35,7 @@ const instagramProfileReport = (backup) => {
     var results = []
     var filename = backup.getFileName(file)
     try {
-      let instagramPlist = bplist.parseBuffer(fs.readFileSync(filename))[0]
+      let instagramPlist = plist.parseFile(filename)
 
       results.push(new KeyValue('last-logged-in-username', instagramPlist))
       results.push(new KeyValue('prefill_fb_email', instagramPlist))

+ 2 - 2
tools/reports/thirdparty/instagram/recent_searches.js

@@ -1,4 +1,4 @@
-const bplist = require('bplist-parser')
+const plist = require('../../../util/plist')
 const fs = require('fs')
 
 // Derive filenames based on domain + file path
@@ -31,7 +31,7 @@ const instagramRecentSearchesReport = (backup) => {
     var results = []
     var filename = backup.getFileName(file)
     try {
-      let instagramPlist = bplist.parseBuffer(fs.readFileSync(filename))[0]
+      let instagramPlist = plist.parseFile(filename)
       let recentSearchesKey = Object.keys(instagramPlist).filter(key => key.indexOf('-blended-search-recent-item-order') !== -1)
       recentSearchesKey.forEach(key => {
         let recentSearches = instagramPlist[key]

+ 2 - 2
tools/reports/thirdparty/spotify/searches.js

@@ -1,4 +1,4 @@
-const bplist = require('bplist-parser')
+const plist = require('../../../util/plist')
 const fs = require('fs')
 
 // Derive filenames based on domain + file path
@@ -31,7 +31,7 @@ const spotifyReport = (backup) => {
   return new Promise((resolve, reject) => {
     var filename = backup.getFileName(database)
     try {
-      let spotifyData = bplist.parseBuffer(fs.readFileSync(filename))[0]
+      let spotifyData = plist.parseFile(filename)
       let spotifyResult = []
 
       console.log('spotifyData', spotifyData)

+ 0 - 2
tools/reports/thirdparty/waze/favorites.js

@@ -1,9 +1,7 @@
 const log = require('../../../util/log')
 const path = require('path')
 const sqlite3 = require('sqlite3')
-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')

+ 0 - 3
tools/reports/thirdparty/waze/places.js

@@ -1,10 +1,7 @@
 const log = require('../../../util/log')
 const path = require('path')
 const sqlite3 = require('sqlite3')
-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')

+ 0 - 2
tools/reports/thirdparty/waze/recents.js

@@ -1,9 +1,7 @@
 const log = require('../../../util/log')
 const path = require('path')
 const sqlite3 = require('sqlite3')
-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')

+ 12 - 13
tools/util/iphone_backup.js

@@ -1,9 +1,8 @@
 const log = require('./log')
 const path = require('path')
 const sqlite3 = require('sqlite3')
-const bplist = require('bplist-parser')
 const fs = require('fs')
-const plist = require('plist')
+const plist = require('./plist')
 
 // Cookie Parser
 const cookieParser = require('./cookies.js')
@@ -17,7 +16,7 @@ const fileHash = require('./backup_filehash')
 // Manifest.mbdb parser
 const manifestMBDBParse = require('./manifest_mbdb_parse')
 
-// Pushstore bplist parser
+// Pushstore plist parser
 const pushstoreParse = require('./pushstore_parse')
 
 const databases = {
@@ -65,22 +64,22 @@ class IPhoneBackup {
       base = path.join(process.env.HOME, '/Library/Application Support/MobileSync/Backup/', id)
     }
 
-    // Parse manifest bplist files
+    // Parse manifest plist files
     try {
       log.verbose('parsing status', base)
-      var status = bplist.parseBuffer(fs.readFileSync(path.join(base, 'Status.plist')))[0]
+      var status = plist.parseFile(path.join(base, 'Status.plist'))
     } catch (e) {
       log.error('Cannot open Status.plist', e)
     }
     try {
       log.verbose('parsing manifest', base)
-      var manifest = bplist.parseBuffer(fs.readFileSync(path.join(base, 'Manifest.plist')))[0]
+      var manifest = plist.parseFile(path.join(base, 'Manifest.plist'))
     } catch (e) {
       log.error('Cannot open Manifest.plist', e)
     }
     try {
       log.verbose('parsing status', base)
-      var info = plist.parse(fs.readFileSync(path.join(base, 'Info.plist'), 'utf8'))
+      var info = plist.parseFile(path.join(base, 'Info.plist'))
     } catch (e) {
       log.error('Cannot open Info.plist', e)
     }
@@ -329,7 +328,7 @@ class IPhoneBackup {
         // The timestamp information is stored in a binary blob named `properties`
         // Which is formatted as a binary PLIST.
         for (var el of rows) {
-          if (el.properties) el.properties = bplist.parseBuffer(el.properties)[0]
+          if (el.properties) el.properties = plist.parseBuffer(el.properties)
 
           // Interestingly, some of these do not have dates attached.
           if (el.properties) {
@@ -571,7 +570,7 @@ class IPhoneBackup {
       var filename = this.getFileName(databases.WiFi)
 
       try {
-        let wifiList = bplist.parseBuffer(fs.readFileSync(filename))[0]
+        let wifiList = plist.parseFile(filename)
         wifiList['List of known networks'] = wifiList['List of known networks']
           .map(el => {
             if (el.BSSID) {
@@ -816,8 +815,8 @@ class IPhoneBackup {
           const pushstores = []
 
           files.forEach((file) => {
-            let plist = bplist.parseBuffer(fs.readFileSync(this.getFileName(file.fileID)))[0]
-            pushstores.push(...pushstoreParse.run(plist))
+            let data = plist.parseFile(this.getFileName(file.fileID))
+            pushstores.push(...pushstoreParse.run(data))
           })
           resolve(pushstores)
         } catch (e) {
@@ -840,8 +839,8 @@ class IPhoneBackup {
 
           let pushstores = []
           files.forEach((file) => {
-            let plist = bplist.parseBuffer(fs.readFileSync(this.getFileName(file.fileID)))[0]
-            pushstores.push(...pushstoreParse.run(plist))
+            let data = plist.parseFile(this.getFileName(file.fileID))
+            pushstores.push(...pushstoreParse.run(data))
           })
           resolve(pushstores)
         } catch (e) {

+ 21 - 0
tools/util/plist.js

@@ -0,0 +1,21 @@
+const fs = require('fs')
+const plist = require('plist')
+const bplist = require('bplist-parser')
+
+function parseBuffer (buffer) {
+  // Binary plists have the marker 'bplist0'
+  if (buffer.slice(0, 7).toString('ascii') === 'bplist0') {
+    // Parse as binary plist
+    data = bplist.parseBuffer(buffer)[0]
+  } else {
+    // Parse as normal plist
+    data = plist.parse(buffer.toString('utf8'))
+  }
+  return data
+}
+
+function parseFile (filePath) {
+  return parseBuffer(fs.readFileSync(filePath))
+}
+
+module.exports = { parseBuffer, parseFile }