chronicle-imessage 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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