chronicle-imessage 0.2.7 → 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: 9aa3bc95443845a57aca895eb7dce6486c89f8458ec2f061dbe84a784ab89dd5
4
- data.tar.gz: a909ca881d4bbbbdd0bfd227bcc4d96f3d84ad5ec63182424e991c3c5e0e5ae7
3
+ metadata.gz: 03a69e13d41a855786b08bea6c849d1b9d8e8d599c7891fe79c8d68dd133bd0d
4
+ data.tar.gz: 50bcf0913088dc140b6665ed40b404402c121b53f90fdd82277163928285ccaf
5
5
  SHA512:
6
- metadata.gz: b787634292b964a2b1309eba7838fd3c8c06bcfcd55a9c6fd30187d9c24a3a0288936dceb6145fc467e2215864f264198c2538a41396e9adda188821b96de5c9
7
- data.tar.gz: a62153bc50f02665f33f5833fafdda3c80accaff1ca75852b0e53270233c65c38094474c251625a80547d613bff8dd7b2d0859d12a7adf718623ccdf68449463
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,21 +10,18 @@ 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
- #### `messages`
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
30
27
  - `input`: (default: ~/Library/Messages/chat.db) Local iMessage sqlite database
@@ -37,7 +34,3 @@ We want messages to have sender/receiver information set properly so we try to i
37
34
  - `icloud_account_id`: Specify an email address that represents your iCloud account ID
38
35
  - `icloud_account_dsid`: Specify iCloud DSID
39
36
  - Can find in Keychain or by running `$ defaults read MobileMeAccounts Accounts`
40
- ### Transformers
41
-
42
- #### `message`
43
- 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,9 +5,10 @@ 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
- r.identifier = 'messages'
11
12
  end
12
13
 
13
14
  setting :input, default: File.join(Dir.home, 'Library', 'Messages', 'chat.db'), required: true
@@ -31,7 +32,7 @@ module Chronicle
31
32
  meta[:my_phone_contact] = @my_phone_contact if @my_phone_contact.values.all?
32
33
  meta[:my_icloud_account] = @my_icloud_account if @my_icloud_account.values.all?
33
34
 
34
- yield Chronicle::ETL::Extraction.new(data: message, meta: meta)
35
+ yield build_extraction(data: message, meta:)
35
36
  end
36
37
  end
37
38
 
@@ -1,165 +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'
9
- r.identifier = 'message'
12
+ r.from_schema = :extraction
13
+ r.to_schema = :chronicle
10
14
  end
11
15
 
12
- def transform
13
- @message = @extraction.data
14
- @participants = @extraction.meta[:participants]
15
- @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])
16
20
 
17
- set_actors
18
- record = build_messaged
19
- record
20
- end
21
-
22
- def timestamp
23
- Time.at(ios_timestamp_to_unix(@message['date'].to_i / 1000000000))
24
- end
25
-
26
- def id
27
- @message['guid']
21
+ build_action(record.data, my_identity, participants)
28
22
  end
29
23
 
30
24
  private
31
25
 
32
- def set_actors
33
- me = build_identity_mine
34
- # Figure out the sender / receiver(s) of a message
35
- case @message['is_from_me']
36
- when 1
37
- @actor = me
38
- @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
39
31
  else
40
- sender = @participants.select{|p| p['id'] == @message['id']}.first
41
- receivers = @participants - [sender]
42
-
43
- @consumers = receivers.collect{|p| build_identity(p)}
44
- @consumers << me
45
- @actor = build_identity(sender)
32
+ agent = participants.select { |p| p.slug == message['id'] }.first
33
+ consumers = participants - [agent] + [my_identity]
46
34
  end
47
- end
48
35
 
49
- def build_messaged
50
- record = ::Chronicle::ETL::Models::Activity.new
51
- record.end_at = timestamp
52
- record.verb = 'messaged'
53
- record.provider_id = id
54
- record.provider = build_provider(@message['service'])
55
- record.dedupe_on = [[:provider, :verb, :provider_id]]
36
+ raise Chronicle::ETL::UntransformableRecordError, 'Could not find agent' unless agent
56
37
 
57
- record.involved = build_message
58
- 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']
59
42
 
60
- record
43
+ r.agent = agent
44
+ r.object = build_message(message, consumers)
45
+ r.dedupe_on = [%i[source source_id type]]
46
+ end
61
47
  end
62
48
 
63
- def build_message
64
- record = ::Chronicle::ETL::Models::Entity.new
65
- record.body = @message['text']
66
- record.provider_id = id
67
- record.represents = 'message'
68
- record.provider = build_provider(@message['service'])
69
- record.dedupe_on = [[:represents, :provider, :provider_id]]
70
-
71
- record.consumers = @consumers
72
- record.contains = @attachments.map{ |a| build_attachment(a)}.compact
73
-
74
- 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
75
58
  end
76
59
 
77
- def build_attachment(attachment)
78
- return unless attachment['mime_type']
79
-
80
- type, subtype = attachment['mime_type'].split("/")
81
- return unless ['image', 'audio', 'video'].include?(type)
82
- return unless attachment['filename']
83
-
84
- attachment_filename = attachment['filename'].gsub("~", Dir.home)
85
- return unless File.exist?(attachment_filename)
86
-
87
- attachment_data = ::Chronicle::ETL::Utils::BinaryAttachments.filename_to_base64(filename: attachment_filename, mimetype: attachment['mime_type'])
88
- recognized_text = ::Chronicle::ETL::Utils::TextRecognition.recognize_in_image(filename: attachment_filename) if type == 'image'
89
-
90
- record = ::Chronicle::ETL::Models::Entity.new
91
- record.provider = 'imessage'
92
- record.provider_id = attachment['guid']
93
- record.represents = type
94
- record.title = File.basename(attachment['filename'])
95
- record.metadata[:ocr_text] = recognized_text if recognized_text
96
- record.dedupe_on = [[:provider, :provider_id, :represents]]
97
-
98
- attachment = ::Chronicle::ETL::Models::Attachment.new
99
- attachment.data = attachment_data
100
- record.attachments = [attachment]
101
-
102
- 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
103
67
  end
104
68
 
105
- def build_identity identity
106
- raise(Chronicle::ETL::UntransformableRecordError, "Could not build record due to missing identity data") unless identity
107
-
108
- record = ::Chronicle::ETL::Models::Entity.new({
109
- represents: 'identity',
110
- slug: identity['id'],
111
- title: identity['full_name'],
112
- provider: identity_provider(@message['service']),
113
- })
114
- record.dedupe_on = [[:represents, :slug, :provider]]
115
- record
116
- 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
117
74
 
118
- def build_identity_mine
119
- case identity_provider(@message['service'])
120
- when 'icloud'
121
- build_identity_mine_icloud
122
- when 'phone'
123
- 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]]
124
81
  end
125
82
  end
126
83
 
127
- def build_identity_mine_icloud
128
- icloud_account = @extraction.meta[:my_icloud_account]
129
- raise(Chronicle::ETL::UntransformableRecordError, "Could not build record due to missing iCloud details. Please provide them through the extractor settings.") unless icloud_account
130
-
131
- record = ::Chronicle::ETL::Models::Entity.new({
132
- represents: 'identity',
133
- provider: 'icloud',
134
- provider_id: icloud_account[:dsid],
135
- title: icloud_account[:display_name],
136
- slug: icloud_account[:id]
137
- })
138
- record.dedupe_on << [:provider, :represents, :slug]
139
- 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
140
96
  end
141
97
 
142
- def build_identity_mine_phone
143
- phone_account = @extraction.meta[:my_phone_contact]
144
- raise(Chronicle::ETL::UntransformableRecordError, "Could not build record due to missing phone details. Please provide them through the extractor settings.") unless phone_account
145
-
146
- record = ::Chronicle::ETL::Models::Entity.new({
147
- represent: 'identity',
148
- provider: 'phone',
149
- title: phone_account[:name],
150
- slug: phone_account[:phone_number]
151
- })
152
- record.dedupe_on << [:provider, :represents, :slug]
153
- 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
154
105
  end
155
106
 
156
- # in the wild, this is either null or sms
157
- def build_provider service
107
+ def entity_source(service)
158
108
  service ? service.downcase : 'imessage'
159
109
  end
160
110
 
161
- # FIXME: should probably try to preserve imessage ids instead of imessage
162
- def identity_provider service
111
+ def agent_source(service)
163
112
  case service
164
113
  # an SMS message is on the 'sms' provider but the provider of the identity used to send it is 'phone'
165
114
  when 'SMS'then 'phone'
@@ -170,12 +119,72 @@ module Chronicle
170
119
  end
171
120
 
172
121
  # FIXME: refactor to shared
173
- def ios_timestamp_to_unix ts
174
- ts + 978307200
122
+ def ios_timestamp_to_unix(ts)
123
+ ts + 978_307_200
175
124
  end
176
- def unix_to_ios_timestamp ts
177
- 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'])
178
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
179
188
  end
180
189
  end
181
190
  end
@@ -1,5 +1,5 @@
1
1
  module Chronicle
2
2
  module Imessage
3
- VERSION = "0.2.7"
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.7
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-09-13 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