chronicle-imessage 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e5b5b2c2b15c1a26c52871284d921960d825d24303b1d872d4d25c8d8782229
4
- data.tar.gz: 5597cc2177ae72c86c2cc9a96b75f29dc5c07b0fe2053304e0e880b4d93919c5
3
+ metadata.gz: 708f7221b523605befa9a52e8fd375d79fc2a82109cf55c04fe145d53a1465b7
4
+ data.tar.gz: 570cbd92f6c52f8149fbebc18f5f961f314a5e3908983a2ce702ce324d2b88ac
5
5
  SHA512:
6
- metadata.gz: bbae018587ad66e2a3ed05a5d7e878058cfac6c747fc283fbc54995f07bbbfc6aacaeddfaa16ae6ceb9d9547f0b4c20d692ce6a4fc059d542ca4621dec0b819c
7
- data.tar.gz: ffc6247be044ebe0cfc58f545b10e7d622ebff3c82dc230c8f412abb61f971bce981bb6edcb58fbbe507a7cb8d639e8b19063ec6b66c2e332584e2c416357ab6
6
+ metadata.gz: e3d7c77e1fe7ee50ab51a4d11566c5c0ab5279b347f1b946c42cb376b6382ed2687af7d0431c5d30ef87bf8bc2c8f58ccf185d2ee5ebd91a99b47af7756ef31d
7
+ data.tar.gz: 51ed17c712516215615f964859ba08cb59deeb6a9d91811865e3b8e226bff1e357fafe04a52fd19a0e545dfe05fc4e309bdcc47853be6c177b80a1e319001643
data/README.md CHANGED
@@ -13,7 +13,6 @@ IMessage importer for [chronicle-etl](https://github.com/chronicle-app/chronicle
13
13
 
14
14
  ```bash
15
15
  gem install chronicle-etl
16
- chronicle-etl connectors:install imessage
17
-
18
- chronicle-etl --extractor imessage --since:"2022-02-07" --transformer imessage --loader table
16
+ chronicle-etl plugins:install imessage
17
+ chronicle-etl --extractor imessage --since "2022-02-07" --transformer imessage
19
18
  ```
@@ -36,8 +36,8 @@ Gem::Specification.new do |spec|
36
36
  spec.require_paths = ["lib"]
37
37
 
38
38
  spec.add_dependency "chronicle-etl", "~> 0.4"
39
- spec.add_dependency "sqlite3", "~> 1.4.2"
40
- spec.add_dependency "phonelib", "~> 0.6.54"
39
+ spec.add_dependency "sqlite3", "~> 1.4"
40
+ spec.add_dependency "phonelib", "~> 0.6"
41
41
 
42
42
  spec.add_development_dependency "bundler", "~> 2.3"
43
43
  spec.add_development_dependency "rake", "~> 13.0.6"
@@ -13,6 +13,11 @@ module Chronicle
13
13
  setting :db, default: File.join(Dir.home, 'Library', 'Messages', 'chat.db'), required: true
14
14
  setting :load_attachments, default: false
15
15
  setting :only_attachments, default: false
16
+ setting :my_phone_number
17
+ setting :my_name
18
+ setting :icloud_account_id
19
+ setting :icloud_account_dsid
20
+ setting :icloud_account_display_name
16
21
 
17
22
  def prepare
18
23
  prepare_data
@@ -23,6 +28,8 @@ module Chronicle
23
28
  meta = {}
24
29
  meta[:participants] = @chats[message['chat_id']]
25
30
  meta[:attachments] = @attachments[message['message_id']] if @attachments
31
+ meta[:my_phone_contact] = @my_phone_contact
32
+ meta[:my_icloud_account] = @my_icloud_account
26
33
 
27
34
  yield Chronicle::ETL::Extraction.new(data: message, meta: meta)
28
35
  end
@@ -37,14 +44,32 @@ module Chronicle
37
44
  def prepare_data
38
45
  @db = SQLite3::Database.new(@config.db, results_as_hash: true)
39
46
  @messages = load_messages
40
- @contacts = LocalContacts.new.contacts
41
47
  @chats = load_chats
42
48
 
49
+ @local_contacts = LocalContacts.new
50
+ @my_phone_contact = load_my_phone_contact(@local_contacts)
51
+ @my_icloud_account = load_my_icloud_account(@local_contacts)
52
+
43
53
  if @config.load_attachments
44
54
  @attachments = load_attachments(@messages.map{|m| m['message_id']})
45
55
  end
46
56
  end
47
57
 
58
+ def load_my_phone_contact(local_contacts)
59
+ {
60
+ phone_number: @config.my_phone_number || local_contacts.my_phone_contact.fetch(:phone_number),
61
+ name: @config.my_name || local_contacts.my_phone_contact.fetch(:full_name)
62
+ }
63
+ end
64
+
65
+ def load_my_icloud_account(local_contacts)
66
+ {
67
+ id: @config.icloud_account_id || local_contacts.my_icloud_account.fetch(:AccountID),
68
+ dsid: @config.icloud_account_dsid || local_contacts.my_icloud_account.fetch(:AccountDSID),
69
+ display_name: @config.icloud_account_display_name || @config.my_name || local_contacts.my_icloud_account.fetch(:DisplayName)
70
+ }
71
+ end
72
+
48
73
  def load_messages
49
74
  conditions = []
50
75
 
@@ -8,9 +8,6 @@ module Chronicle
8
8
  r.description = 'a row from a local imessage database'
9
9
  end
10
10
 
11
- setting :my_phone_slug, required: true
12
- setting :my_name, required: true
13
-
14
11
  def transform
15
12
  @message = @extraction.data
16
13
  @participants = @extraction.meta[:participants]
@@ -118,14 +115,40 @@ module Chronicle
118
115
  end
119
116
 
120
117
  def build_identity_mine
118
+ case identity_provider(@message['service'])
119
+ when 'icloud'
120
+ build_identity_mine_icloud
121
+ when 'phone'
122
+ build_identity_mine_phone
123
+ end
124
+ end
125
+
126
+ def build_identity_mine_icloud
127
+ icloud_account = @extraction.meta[:my_icloud_account]
128
+ raise(UntransformableRecordError, "Missing iCloud account information") unless icloud_account
129
+
121
130
  record = ::Chronicle::ETL::Models::Entity.new({
122
- represents: 'identity',
123
- slug: @config.my_phone_slug,
124
- title: @config.my_name,
125
- provider: identity_provider(@message['service']),
126
- provider_id: @message['account_guid']
131
+ represent: 'identity',
132
+ provider: 'icloud',
133
+ provider_id: icloud_account[:dsid],
134
+ title: icloud_account[:display_name],
135
+ slug: icloud_account[:id]
136
+ })
137
+ record.dedupe_on << [:provider, :represents, :slug]
138
+ record
139
+ end
140
+
141
+ def build_identity_mine_phone
142
+ phone_account = @extraction.meta[:my_phone_contact]
143
+ raise(UntransformableRecordError, "Missing own phone contact information") unless phone_account
144
+
145
+ record = ::Chronicle::ETL::Models::Entity.new({
146
+ represent: 'identity',
147
+ provider: 'phone',
148
+ title: phone_account[:name],
149
+ slug: phone_account[:phone_number]
127
150
  })
128
- record.dedupe_on = [[:represents, :slug, :provider], [:represents, :provider, :provider_id]]
151
+ record.dedupe_on << [:provider, :represents, :slug]
129
152
  record
130
153
  end
131
154
 
@@ -23,6 +23,14 @@ module Chronicle
23
23
  end
24
24
  end
25
25
 
26
+ def my_phone_contact
27
+ @my_phone_contact ||= load_my_phone_contact
28
+ end
29
+
30
+ def my_icloud_account
31
+ @my_icloud_account ||= load_my_icloud_account
32
+ end
33
+
26
34
  # The synced address book doesn't have a stable folder location so we
27
35
  # have to search for it
28
36
  def find_local_icloud_address_book
@@ -30,6 +38,38 @@ module Chronicle
30
38
  Dir.glob(pattern).first
31
39
  end
32
40
 
41
+ def load_my_icloud_account
42
+ @my_icloud_account || begin
43
+ output = `defaults read MobileMeAccounts Accounts | plutil -convert json -r -o - -- -`
44
+ JSON.parse(output, symbolize_names: true).first
45
+ end
46
+ end
47
+
48
+ def load_my_phone_contact
49
+ sql = <<-SQL
50
+ SELECT
51
+ ZABCDPHONENUMBER.ZFULLNUMBER AS identifier,
52
+ ZABCDRECORD.ZFIRSTNAME as first_name,
53
+ ZABCDRECORD.ZLASTNAME as last_name
54
+ FROM
55
+ ZABCDRECORD,
56
+ ZABCDPHONENUMBER
57
+ WHERE
58
+ ZABCDRECORD.Z_PK = ZABCDPHONENUMBER.ZOWNER
59
+ AND ZABCDRECORD.zcontainerwherecontactisme IS NOT NULL
60
+ SQL
61
+
62
+ results = @db.execute(sql)
63
+
64
+ guessed_number = results.first
65
+ return unless guessed_number
66
+
67
+ {
68
+ phone_number: Phonelib.parse(guessed_number['identifier'], "US").e164,
69
+ full_name: "#{guessed_number['first_name']} #{guessed_number['last_name']}"
70
+ }
71
+ end
72
+
33
73
  def load_phone_numbers
34
74
  sql = <<-SQL
35
75
  SELECT
@@ -1,5 +1,5 @@
1
1
  module Chronicle
2
2
  module Imessage
3
- VERSION = "0.2.0"
3
+ VERSION = "0.2.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronicle-imessage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Louis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-02-25 00:00:00.000000000 Z
11
+ date: 2022-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chronicle-etl
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.4.2
33
+ version: '1.4'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.4.2
40
+ version: '1.4'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: phonelib
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.6.54
47
+ version: '0.6'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.6.54
54
+ version: '0.6'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -122,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
124
  requirements: []
125
- rubygems_version: 3.1.6
125
+ rubygems_version: 3.3.9
126
126
  signing_key:
127
127
  specification_version: 4
128
128
  summary: iMessage importer for Chronicle