chronicle-imessage 0.2.6 → 0.3.0

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: 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