chronicle-imessage 0.2.6 → 0.3.0

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: 487662c0e1aa17dde6c9463a21e7c47ff154680b56b1b4b0bafe90f0697300fa
4
- data.tar.gz: 66a2ac859488c93b9a56a0cd0a1d57dfa603fad53deced6d569f2e9da575b09f
3
+ metadata.gz: 03a69e13d41a855786b08bea6c849d1b9d8e8d599c7891fe79c8d68dd133bd0d
4
+ data.tar.gz: 50bcf0913088dc140b6665ed40b404402c121b53f90fdd82277163928285ccaf
5
5
  SHA512:
6
- metadata.gz: 1eedfca866b70d9711b54078b52086b578d1fa90c1f444d1f6df3af52245cec1960b461d22d0e39a009a56b7b3063e5c725c848f5cfddced5e5dd0be3e4bb057
7
- data.tar.gz: bbad7a7002e5806eb81076e1360794dea1cbf75392700dd88496b447a516e23bacb170ca165dc18ad3a61f7fbf5c5a1360b5263dd9402820ea728b946ac2a430
6
+ metadata.gz: 4c98ad41fdafab157edaa9549e7ef560ac851997bf2773dd1351fbcbae2f5f2dea2376dedae94aa6a7d1fc7f4a5960b6fc3677ba3b27424455435251dcd87c63
7
+ data.tar.gz: 2197b73726b4d55f9e2d5e2b991f52a3b6524e377203cd389663ad744dfdb39d8346e1c4b12a042503bac08d2278a8e6bde221f48d2774189fe2b239f18d5f78
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ inherit_gem:
2
+ chronicle-core: .rubocop-plugin.yml
data/README.md CHANGED
@@ -10,23 +10,21 @@ Access your iMessage messages and attachments using the command line with this p
10
10
  $ gem install chronicle-etl
11
11
  $ chronicle-etl plugins:install imessage
12
12
 
13
- # Load messages since February 7
14
- $ chronicle-etl --extractor imessage --transformer imessage --since "2022-02-07"
13
+ # Load messages from the last week
14
+ $ chronicle-etl --extractor imessage --schema chronicle --since 1w
15
15
 
16
16
  # Of the latest 1000 messages received, who were the top senders?
17
- $ chronicle-etl -e imessage -t imessage --limit 1000 --no-header-row --fields actor.title | sort | uniq -c | sort -nr
18
-
19
- # Get the raw query results for the latest 10 messages and save as a CSV
20
- $ chronicle-etl -e imessage --loader csv --limit 10 -o imessages.csv
17
+ $ chronicle-etl -e imessage --schema chronicle --limit 1000 --fields agent.name | sort | uniq -c | sort -nr
21
18
  ```
22
19
 
23
20
  ## Available Connectors
24
21
  ### Extractors
25
22
 
26
- #### `imessage`
27
- Extractor for importing messages and attachments from local macOS iMessage install (`~/Library/Messages/chat.db`)
23
+ #### `message`
24
+ Extractor for importing messages and attachments from local macOS iMessage install (via local cache at `~/Library/Messages/chat.db`)
28
25
 
29
26
  ##### Settings
27
+ - `input`: (default: ~/Library/Messages/chat.db) Local iMessage sqlite database
30
28
  - `load_attachments`: (default: false) Whether to load message attachments
31
29
  - `only_attachments`: (default: false) Whether to load only messages with attachments
32
30
 
@@ -36,7 +34,3 @@ We want messages to have sender/receiver information set properly so we try to i
36
34
  - `icloud_account_id`: Specify an email address that represents your iCloud account ID
37
35
  - `icloud_account_dsid`: Specify iCloud DSID
38
36
  - Can find in Keychain or by running `$ defaults read MobileMeAccounts Accounts`
39
- ### Transformers
40
-
41
- #### `imessage`
42
- Transform an iMessage message into Chronicle Schema
data/bin/console CHANGED
@@ -1,14 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "chronicle/imessage"
3
+ require 'bundler/setup'
4
+ require 'chronicle/imessage'
5
5
 
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
6
+ require 'pry'
7
+ Pry.start
@@ -1,44 +1,49 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "chronicle/imessage/version"
3
+ require 'chronicle/imessage/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "chronicle-imessage"
6
+ spec.name = 'chronicle-imessage'
8
7
  spec.version = Chronicle::Imessage::VERSION
9
- spec.authors = ["Andrew Louis"]
10
- spec.email = ["andrew@hyfen.net"]
8
+ spec.authors = ['Andrew Louis']
9
+ spec.email = ['andrew@hyfen.net']
10
+
11
+ spec.summary = 'iMessage importer for Chronicle'
12
+ spec.description = 'Connectors for iMessage'
13
+ spec.homepage = 'https://github.com/chronicle-app/chronicle-imessage'
11
14
 
12
- spec.summary = "iMessage importer for Chronicle"
13
- spec.description = "Connectors for iMessage"
14
- spec.homepage = "https://github.com/chronicle-app/chronicle-imessage"
15
+ spec.required_ruby_version = '>= 3.1'
15
16
 
16
17
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
18
  # to allow pushing to a single host or delete this section to allow pushing to any host.
18
19
  if spec.respond_to?(:metadata)
19
- spec.metadata['allowed_push_host'] = "https://rubygems.org"
20
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
20
21
 
21
- spec.metadata["homepage_uri"] = spec.homepage
22
- spec.metadata["source_code_uri"] = "https://github.com/chronicle-app/chronicle-imessage"
23
- spec.metadata["changelog_uri"] = "https://github.com/chronicle-app/chronicle-imessage"
22
+ spec.metadata['homepage_uri'] = spec.homepage
23
+ spec.metadata['source_code_uri'] = 'https://github.com/chronicle-app/chronicle-imessage'
24
+ spec.metadata['changelog_uri'] = 'https://github.com/chronicle-app/chronicle-imessage'
24
25
  else
25
- raise "RubyGems 2.0 or newer is required to protect against " \
26
- "public gem pushes."
26
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
27
+ 'public gem pushes.'
27
28
  end
28
29
 
29
30
  # Specify which files should be added to the gem when it is released.
30
31
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
31
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
32
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
32
33
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
33
34
  end
34
- spec.bindir = "exe"
35
+ spec.bindir = 'exe'
35
36
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
36
- spec.require_paths = ["lib"]
37
-
38
- spec.add_dependency "chronicle-etl", "~> 0.5"
39
- spec.add_dependency "sqlite3", "~> 1.4"
40
- spec.add_dependency "phonelib", "~> 0.6"
41
-
42
- spec.add_development_dependency "bundler", "~> 2.3"
43
- spec.add_development_dependency "rake", "~> 13.0.6"
37
+ spec.require_paths = ['lib']
38
+ spec.metadata['rubygems_mfa_required'] = 'true'
39
+
40
+ spec.add_dependency 'chronicle-core', '~> 0.3'
41
+ spec.add_dependency 'chronicle-etl', '~> 0.6'
42
+ spec.add_dependency 'phonelib', '~> 0.6'
43
+ spec.add_dependency 'sqlite3', '~> 1.4'
44
+
45
+ spec.add_development_dependency 'bundler', '~> 2.3'
46
+ spec.add_development_dependency 'pry-byebug', '~> 3.10'
47
+ spec.add_development_dependency 'rake', '~> 13.0'
48
+ spec.add_development_dependency 'rubocop', '~> 1.63'
44
49
  end
@@ -5,11 +5,13 @@ module Chronicle
5
5
  module Imessage
6
6
  class ImessageExtractor < Chronicle::ETL::Extractor
7
7
  register_connector do |r|
8
- r.provider = 'imessage'
8
+ r.source = :imessage
9
+ r.type = :message
10
+ r.strategy = :local_db
9
11
  r.description = 'a local imessage database'
10
12
  end
11
13
 
12
- setting :db, default: File.join(Dir.home, 'Library', 'Messages', 'chat.db'), required: true
14
+ setting :input, default: File.join(Dir.home, 'Library', 'Messages', 'chat.db'), required: true
13
15
  setting :load_attachments, default: false
14
16
  setting :only_attachments, default: false
15
17
  setting :my_phone_number
@@ -30,7 +32,7 @@ module Chronicle
30
32
  meta[:my_phone_contact] = @my_phone_contact if @my_phone_contact.values.all?
31
33
  meta[:my_icloud_account] = @my_icloud_account if @my_icloud_account.values.all?
32
34
 
33
- yield Chronicle::ETL::Extraction.new(data: message, meta: meta)
35
+ yield build_extraction(data: message, meta:)
34
36
  end
35
37
  end
36
38
 
@@ -40,8 +42,12 @@ module Chronicle
40
42
 
41
43
  private
42
44
 
45
+ def db_file
46
+ [@config.input].flatten.first
47
+ end
48
+
43
49
  def prepare_data
44
- @db = SQLite3::Database.new(@config.db, results_as_hash: true)
50
+ @db = SQLite3::Database.new(db_file, results_as_hash: true)
45
51
  @local_contacts = LocalContacts.new
46
52
  @contacts = @local_contacts.contacts
47
53
 
@@ -1,164 +1,114 @@
1
1
  require 'chronicle/etl'
2
+ require 'chronicle/models'
2
3
 
3
4
  module Chronicle
4
- module Imessage
5
+ module Imessage
5
6
  class ImessageTransformer < Chronicle::ETL::Transformer
6
7
  register_connector do |r|
7
- r.provider = 'imessage'
8
+ r.source = :imessage
9
+ r.type = :message
10
+ r.strategy = :local_db
8
11
  r.description = 'a row from a local imessage database'
12
+ r.from_schema = :extraction
13
+ r.to_schema = :chronicle
9
14
  end
10
15
 
11
- def transform
12
- @message = @extraction.data
13
- @participants = @extraction.meta[:participants]
14
- @attachments = @extraction.meta[:attachments] || []
16
+ def transform(record)
17
+ participants = record.extraction.meta[:participants].map { |p| build_identity(record.data, p) }
18
+ my_identity = build_identity_mine(record.data, record.extraction.meta[:my_icloud_account],
19
+ record.extraction.meta[:my_phone_contact])
15
20
 
16
- set_actors
17
- record = build_messaged
18
- record
19
- end
20
-
21
- def timestamp
22
- Time.at(ios_timestamp_to_unix(@message['date'].to_i / 1000000000))
23
- end
24
-
25
- def id
26
- @message['guid']
21
+ build_action(record.data, my_identity, participants)
27
22
  end
28
23
 
29
24
  private
30
25
 
31
- def set_actors
32
- me = build_identity_mine
33
- # Figure out the sender / receiver(s) of a message
34
- case @message['is_from_me']
35
- when 1
36
- @actor = me
37
- @consumers = @participants.collect{|p| build_identity(p)}
26
+ def build_action(message, my_identity, participants)
27
+ if message['is_from_me'] == 1
28
+ participants -= [my_identity]
29
+ agent = my_identity
30
+ consumers = participants
38
31
  else
39
- sender = @participants.select{|p| p['id'] == @message['id']}.first
40
- receivers = @participants - [sender]
41
-
42
- @consumers = receivers.collect{|p| build_identity(p)}
43
- @consumers << me
44
- @actor = build_identity(sender)
32
+ agent = participants.select { |p| p.slug == message['id'] }.first
33
+ consumers = participants - [agent] + [my_identity]
45
34
  end
46
- end
47
35
 
48
- def build_messaged
49
- record = ::Chronicle::ETL::Models::Activity.new
50
- record.end_at = timestamp
51
- record.verb = 'messaged'
52
- record.provider_id = id
53
- record.provider = build_provider(@message['service'])
54
- record.dedupe_on = [[:provider, :verb, :provider_id]]
36
+ raise Chronicle::ETL::UntransformableRecordError, 'Could not find agent' unless agent
55
37
 
56
- record.involved = build_message
57
- record.actor = @actor
38
+ Chronicle::Models::CommunicateAction.new do |r|
39
+ r.end_time = Time.at(ios_timestamp_to_unix(message['date'].to_i / 1_000_000_000))
40
+ r.source = entity_source(message['service'])
41
+ r.source_id = message['guid']
58
42
 
59
- record
43
+ r.agent = agent
44
+ r.object = build_message(message, consumers)
45
+ r.dedupe_on = [%i[source source_id type]]
46
+ end
60
47
  end
61
48
 
62
- def build_message
63
- record = ::Chronicle::ETL::Models::Entity.new
64
- record.body = @message['text']
65
- record.provider_id = id
66
- record.represents = 'message'
67
- record.provider = build_provider(@message['service'])
68
- record.dedupe_on = [[:represents, :provider, :provider_id]]
69
-
70
- record.consumers = @consumers
71
- record.contains = @attachments.map{ |a| build_attachment(a)}.compact
72
-
73
- record
49
+ def build_message(message, consumers)
50
+ Chronicle::Models::Message.new do |r|
51
+ # TODO: handle text that's in `attributedBody`
52
+ r.text = normalized_body(message)
53
+ r.source = 'imessage'
54
+ r.source_id = message['guid']
55
+ r.recipient = consumers
56
+ r.dedupe_on = [%i[source source_id type]]
57
+ end
74
58
  end
75
59
 
76
- def build_attachment(attachment)
77
- return unless attachment['mime_type']
78
-
79
- type, subtype = attachment['mime_type'].split("/")
80
- return unless ['image', 'audio', 'video'].include?(type)
81
- return unless attachment['filename']
82
-
83
- attachment_filename = attachment['filename'].gsub("~", Dir.home)
84
- return unless File.exist?(attachment_filename)
85
-
86
- attachment_data = ::Chronicle::ETL::Utils::BinaryAttachments.filename_to_base64(filename: attachment_filename, mimetype: attachment['mime_type'])
87
- recognized_text = ::Chronicle::ETL::Utils::TextRecognition.recognize_in_image(filename: attachment_filename) if type == 'image'
88
-
89
- record = ::Chronicle::ETL::Models::Entity.new
90
- record.provider = 'imessage'
91
- record.provider_id = attachment['guid']
92
- record.represents = type
93
- record.title = File.basename(attachment['filename'])
94
- record.metadata[:ocr_text] = recognized_text if recognized_text
95
- record.dedupe_on = [[:provider, :provider_id, :represents]]
96
-
97
- attachment = ::Chronicle::ETL::Models::Attachment.new
98
- attachment.data = attachment_data
99
- record.attachments = [attachment]
100
-
101
- record
60
+ def build_identity_mine(message, my_icloud_account, my_phone_contact)
61
+ case agent_source(message['service'])
62
+ when 'icloud'
63
+ build_identity_mine_icloud(my_icloud_account)
64
+ when 'phone'
65
+ build_identity_mine_phone(my_phone_contact)
66
+ end
102
67
  end
103
68
 
104
- def build_identity identity
105
- raise(Chronicle::ETL::UntransformableRecordError, "Could not build record due to missing identity data") unless identity
106
-
107
- record = ::Chronicle::ETL::Models::Entity.new({
108
- represents: 'identity',
109
- slug: identity['id'],
110
- title: identity['full_name'],
111
- provider: identity_provider(@message['service']),
112
- })
113
- record.dedupe_on = [[:represents, :slug, :provider]]
114
- record
115
- end
69
+ def build_identity_mine_icloud(icloud_account)
70
+ unless icloud_account
71
+ raise(Chronicle::ETL::UntransformableRecordError,
72
+ 'Could not build record due to missing iCloud details. Please provide them through the extractor settings.')
73
+ end
116
74
 
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
75
+ Chronicle::Models::Person.new do |r|
76
+ r.name = icloud_account[:display_name]
77
+ r.source = 'icloud'
78
+ r.slug = icloud_account[:id]
79
+ r.source_id = icloud_account[:dsid]
80
+ r.dedupe_on = [%i[type source source_id]]
123
81
  end
124
82
  end
125
83
 
126
- def build_identity_mine_icloud
127
- icloud_account = @extraction.meta[:my_icloud_account]
128
- raise(Chronicle::ETL::UntransformableRecordError, "Could not build record due to missing iCloud details. Please provide them through the extractor settings.") unless icloud_account
129
-
130
- record = ::Chronicle::ETL::Models::Entity.new({
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
84
+ def build_identity_mine_phone(phone_account)
85
+ unless phone_account
86
+ raise(Chronicle::ETL::UntransformableRecordError,
87
+ 'Could not build record due to missing phone details. Please provide them through the extractor settings.')
88
+ end
89
+
90
+ Chronicle::Models::Person.new do |r|
91
+ r.name = phone_account[:name]
92
+ r.source = 'phone'
93
+ r.slug = phone_account[:phone_number]
94
+ r.dedupe_on = [%i[type source slug]]
95
+ end
139
96
  end
140
97
 
141
- def build_identity_mine_phone
142
- phone_account = @extraction.meta[:my_phone_contact]
143
- raise(Chronicle::ETL::UntransformableRecordError, "Could not build record due to missing phone details. Please provide them through the extractor settings.") 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]
150
- })
151
- record.dedupe_on << [:provider, :represents, :slug]
152
- record
98
+ def build_identity(message, identity)
99
+ Chronicle::Models::Person.new do |r|
100
+ r.name = identity['full_name']
101
+ r.source = agent_source(message['service'])
102
+ r.slug = identity['id']
103
+ r.dedupe_on = [%i[type source slug]]
104
+ end
153
105
  end
154
106
 
155
- # in the wild, this is either null or sms
156
- def build_provider service
107
+ def entity_source(service)
157
108
  service ? service.downcase : 'imessage'
158
109
  end
159
110
 
160
- # FIXME: should probably try to preserve imessage ids instead of imessage
161
- def identity_provider service
111
+ def agent_source(service)
162
112
  case service
163
113
  # an SMS message is on the 'sms' provider but the provider of the identity used to send it is 'phone'
164
114
  when 'SMS'then 'phone'
@@ -169,12 +119,72 @@ module Chronicle
169
119
  end
170
120
 
171
121
  # FIXME: refactor to shared
172
- def ios_timestamp_to_unix ts
173
- ts + 978307200
122
+ def ios_timestamp_to_unix(ts)
123
+ ts + 978_307_200
174
124
  end
175
- def unix_to_ios_timestamp ts
176
- ts - 978307200
125
+
126
+ def unix_to_ios_timestamp(ts)
127
+ ts - 978_307_200
128
+ end
129
+
130
+ def normalized_body(message)
131
+ message['text'] || normalize_attributed_body(message['attributedBody'])
177
132
  end
133
+
134
+ # Based on https://github.com/kndonlee/meds/blob/224be297e8e709e6a52aca5fa05ec42d34af1aef/all_messages.rb#L31
135
+ def normalize_attributed_body(body)
136
+ return unless body
137
+
138
+ attributed_body = body.force_encoding('UTF-8').encode('UTF-8', invalid: :replace)
139
+
140
+ return unless attributed_body.include?('NSNumber')
141
+
142
+ attributed_body = attributed_body.split('NSNumber')[0]
143
+ return unless attributed_body.include?('NSString')
144
+
145
+ attributed_body = attributed_body.split('NSString')[1]
146
+ return unless attributed_body.include?('NSDictionary')
147
+
148
+ attributed_body = attributed_body.split('NSDictionary')[0]
149
+ attributed_body = attributed_body[6..-13]
150
+
151
+ if attributed_body =~ /^.[\u0000]/
152
+ attributed_body.gsub(/^.[\u0000]/, '')
153
+ else
154
+ attributed_body
155
+ end
156
+ end
157
+
158
+ # def build_attachment(attachment)
159
+ # return unless attachment['mime_type']
160
+
161
+ # type, subtype = attachment['mime_type'].split('/')
162
+ # return unless %w[image audio video].include?(type)
163
+ # return unless attachment['filename']
164
+
165
+ # attachment_filename = attachment['filename'].gsub('~', Dir.home)
166
+ # return unless File.exist?(attachment_filename)
167
+
168
+ # attachment_data = ::Chronicle::ETL::Utils::BinaryAttachments.filename_to_base64(filename: attachment_filename,
169
+ # mimetype: attachment['mime_type'])
170
+ # if type == 'image'
171
+ # recognized_text = ::Chronicle::ETL::Utils::TextRecognition.recognize_in_image(filename: attachment_filename)
172
+ # end
173
+
174
+ # record = ::Chronicle::ETL::Models::Entity.new
175
+ # record.provider = 'imessage'
176
+ # record.provider_id = attachment['guid']
177
+ # record.represents = type
178
+ # record.title = File.basename(attachment['filename'])
179
+ # record.metadata[:ocr_text] = recognized_text if recognized_text
180
+ # record.dedupe_on = [%i[provider provider_id represents]]
181
+
182
+ # attachment = ::Chronicle::ETL::Models::Attachment.new
183
+ # attachment.data = attachment_data
184
+ # record.attachments = [attachment]
185
+
186
+ # record
187
+ # end
178
188
  end
179
189
  end
180
190
  end
@@ -1,5 +1,5 @@
1
1
  module Chronicle
2
2
  module Imessage
3
- VERSION = "0.2.6"
3
+ VERSION = '0.3.0'.freeze
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
- require "chronicle/imessage/version"
2
- require "chronicle/imessage/imessage_extractor"
3
- require "chronicle/imessage/imessage_transformer"
4
- require "chronicle/imessage/local_contacts"
1
+ require 'chronicle/imessage/version'
2
+ require 'chronicle/imessage/imessage_extractor'
3
+ require 'chronicle/imessage/imessage_transformer'
4
+ require 'chronicle/imessage/local_contacts'
5
5
 
6
6
  module Chronicle
7
7
  module Imessage
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronicle-imessage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.3.0
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-03-25 00:00:00.000000000 Z
11
+ date: 2024-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: chronicle-etl
14
+ name: chronicle-core
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.5'
19
+ version: '0.3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.5'
26
+ version: '0.3'
27
27
  - !ruby/object:Gem::Dependency
28
- name: sqlite3
28
+ name: chronicle-etl
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.4'
33
+ version: '0.6'
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'
40
+ version: '0.6'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: phonelib
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.4'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.4'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -66,20 +80,48 @@ dependencies:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '2.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.10'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: rake
71
99
  requirement: !ruby/object:Gem::Requirement
72
100
  requirements:
73
101
  - - "~>"
74
102
  - !ruby/object:Gem::Version
75
- version: 13.0.6
103
+ version: '13.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '13.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.63'
76
118
  type: :development
77
119
  prerelease: false
78
120
  version_requirements: !ruby/object:Gem::Requirement
79
121
  requirements:
80
122
  - - "~>"
81
123
  - !ruby/object:Gem::Version
82
- version: 13.0.6
124
+ version: '1.63'
83
125
  description: Connectors for iMessage
84
126
  email:
85
127
  - andrew@hyfen.net
@@ -88,6 +130,7 @@ extensions: []
88
130
  extra_rdoc_files: []
89
131
  files:
90
132
  - ".gitignore"
133
+ - ".rubocop.yml"
91
134
  - CODE_OF_CONDUCT.md
92
135
  - Gemfile
93
136
  - README.md
@@ -107,6 +150,7 @@ metadata:
107
150
  homepage_uri: https://github.com/chronicle-app/chronicle-imessage
108
151
  source_code_uri: https://github.com/chronicle-app/chronicle-imessage
109
152
  changelog_uri: https://github.com/chronicle-app/chronicle-imessage
153
+ rubygems_mfa_required: 'true'
110
154
  post_install_message:
111
155
  rdoc_options: []
112
156
  require_paths:
@@ -115,14 +159,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
115
159
  requirements:
116
160
  - - ">="
117
161
  - !ruby/object:Gem::Version
118
- version: '0'
162
+ version: '3.1'
119
163
  required_rubygems_version: !ruby/object:Gem::Requirement
120
164
  requirements:
121
165
  - - ">="
122
166
  - !ruby/object:Gem::Version
123
167
  version: '0'
124
168
  requirements: []
125
- rubygems_version: 3.3.3
169
+ rubygems_version: 3.4.10
126
170
  signing_key:
127
171
  specification_version: 4
128
172
  summary: iMessage importer for Chronicle