pushstore_parse.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. const ARCHIVER_KEY = '$archiver'
  2. const TOP_KEY = '$top'
  3. const OBJECTS_KEY = '$objects'
  4. const CLASS_KEY = '$class'
  5. const CLASSNAME_KEY = '$classname'
  6. const NS_OBJECTS = 'NS.objects'
  7. const NS_KEYS = 'NS.keys'
  8. const NS_TIME = 'NS.time'
  9. const NS_MUTABLE_DICTIONARY = 'NSMutableDictionary'
  10. const DEFAULT_KEYS = ['AppNotificationCreationDate',
  11. 'RequestedDate',
  12. 'TriggerDate',
  13. 'AppNotificationMessage']
  14. const UNIX_OFFSET = 978307200
  15. const run = (pushstore) => {
  16. const pushstoreEntries = []
  17. if (is_valid_pushstore(pushstore)) {
  18. let top = get_top(pushstore)
  19. if (top == -1) {
  20. throw "Unable to get $top location!"
  21. return false
  22. }
  23. pushstore.objects_list = pushstore[OBJECTS_KEY]
  24. let pointer_to_entries = load_from_location(pushstore, top)
  25. pointer_to_entries['objects'].every((entry_offset) => {
  26. let entry_dict = make_entry_dict(pushstore, load_from_location(pushstore, entry_offset))
  27. let formatted = format_entry(pushstore, entry_dict)
  28. pushstoreEntries.push(formatted)
  29. return true
  30. })
  31. }
  32. return pushstoreEntries
  33. }
  34. const is_valid_pushstore = (pushstore) => {
  35. // Check version and archiver key
  36. return pushstore[ARCHIVER_KEY] === "NSKeyedArchiver"
  37. }
  38. const get_top = (pushstore) => {
  39. // Find pointer in $objects to starting point
  40. try {
  41. return parseInt(pushstore[TOP_KEY]['root']['UID'])
  42. } catch (e) {
  43. throw e
  44. }
  45. }
  46. const load_from_location = (pushstore, offset) => {
  47. // Load objects (and keys) from a location
  48. let loaded_dict = {}
  49. let start = pushstore.objects_list[offset]
  50. //pushstore.start = start
  51. let loaded_class = get_classname_at(start, pushstore)
  52. if (!loaded_class) {
  53. throw "Unable to determine $classname of key!"
  54. }
  55. loaded_dict['class'] = loaded_class
  56. loaded_dict['objects'] = start[NS_OBJECTS].map((x) => parseInt(x['UID']))
  57. if (loaded_class === NS_MUTABLE_DICTIONARY) {
  58. loaded_dict['keys'] = start[NS_KEYS].map((x) => parseInt(x['UID']))
  59. }
  60. return loaded_dict
  61. }
  62. const get_classname_at = (start, pushstore) => {
  63. // Get the classname of the object referenced
  64. try {
  65. return pushstore.objects_list[parseInt(start[CLASS_KEY]['UID'])][CLASSNAME_KEY]
  66. } catch (e) {
  67. throw e
  68. }
  69. }
  70. const make_entry_dict = (pushstore, loaded) => {
  71. // Make dict from offset and keys
  72. let entries = {}
  73. let offsets = loaded['objects']
  74. let keys = loaded['keys']
  75. let i = 0
  76. while (i < keys.length) {
  77. entries[pushstore.objects_list[keys[i]]] = pushstore.objects_list[offsets[i]]
  78. i++
  79. }
  80. return entries
  81. }
  82. const format_entry = (pushstore, entry_dict) => {
  83. // Format each of the entries
  84. let formatted = {}
  85. formatted['AppNotificationCreationDate'] = safe_get_time(pushstore, entry_dict, 'AppNotificationCreationDate')
  86. formatted['RequestedDate'] = safe_get_time(pushstore, entry_dict, 'RequestedDate')
  87. formatted['TriggerDate'] = safe_get_time(pushstore, entry_dict, 'TriggerDate')
  88. formatted['AppNotificationMessage'] = entry_dict['AppNotificationMessage']
  89. formatted['AppNotificationTitle'] = entry_dict['AppNotificationTitle'] ? entry_dict['AppNotificationTitle'] : 'N/A'
  90. return formatted
  91. }
  92. const safe_get_time = (pushstore, in_dict, key) => {
  93. // Safely get a timestamp
  94. try {
  95. if (in_dict && in_dict[key] && in_dict[key][NS_TIME])
  96. return to_real_time(in_dict[key][NS_TIME])
  97. return 'N/A'
  98. } catch (e) {
  99. throw e
  100. }
  101. }
  102. const to_real_time = (ns_time) => {
  103. // Convert an NSTime to UTC timestamp string
  104. return new Date((ns_time + UNIX_OFFSET) * 1000).toISOString()
  105. }
  106. module.exports = {
  107. run: run
  108. }