heya 0.1.0 → 0.2.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: 1aedd0a6d25dc8185eacb59e5e279f6dc6c2135d3980005c1d5b5c82a351c403
4
- data.tar.gz: c6007415e758afe5d998ebbe1e9b8ae920e25e4c6abffa9da6c6a9fb1d713ae7
3
+ metadata.gz: 125b5f898dd3d7841fd0e50ae05d424ec56d2818bb011a43a083f224d15aa3ea
4
+ data.tar.gz: 23a1fd76278729817ab0317dff81ab816cabd9f09b323e8f723cb5c8f9186eff
5
5
  SHA512:
6
- metadata.gz: fce537c6eefe599dd9aa3b2be7fdb2c7ce0839c15a7e82256aaf168691103a57ee4e76b146d5cc8d91e7111b546ecbde3041e01e98ff59ac98ef74ce42935fb0
7
- data.tar.gz: bceb804f1400eccc44cbacd182007160bbec6b5595613224fff5792596b2661abeeb259bc36e7222bc043cf341754fa8cffb33462828836978fb980b75d5d453
6
+ metadata.gz: 22b4d72ffa9e69068ce5a77008b76047cf3f1379d330f233b0a4f174a6a89d3a91ab3353e1941b4b1262a4898316cdc1b14e3842468e4fd9bbffa301234c3e62
7
+ data.tar.gz: bc5c5604c1e1d95adb14fe4435817431c4af2f471a5df7d6bfd4ec100d6a5607cbd4121a31d66660cde7e9a892b84126bf6b6e2d15676afbd36af2fad958910e
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.2.0] - 2020-04-14
10
+ ### Added
11
+ - Added licensing.
12
+ - Added `rescue_from` (rescuable) in campaigns.
13
+
9
14
  ## [0.1.0] - 2020-03-19
10
15
  ### Added
11
16
  - Initial release. 👋
data/README.md CHANGED
@@ -1,30 +1,9 @@
1
1
  # Heya 👋
2
2
  ![Test](https://github.com/honeybadger-io/heya/workflows/Test/badge.svg)
3
+ [![Gem Version](https://badge.fury.io/rb/heya.svg)](https://badge.fury.io/rb/heya)
3
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/a6416e63ffc426715857/maintainability)](https://codeclimate.com/github/honeybadger-io/heya/maintainability)
4
5
 
5
- Heya is a customer communication and automation framework for Ruby on Rails. It's as robust as the hosted alternatives, without the integration and compliance nightmare.
6
-
7
- ## Why Heya?
8
- Imagine onboarding and engaging your users with full access to their data, without maintaining a single 3rd-party integration or stressing over compliance. That's Heya: a new way to email your users.
9
-
10
- Heya lives inside your Rails app, giving you full access to your customer data with the power of Ruby and Rails for building automated email campaigns.
11
-
12
- If you've ever used 3rd-party email or marketing platforms, you've felt the pain of integrating, syncing customer data, and maintaining complex logic and rules--all of which is unnecessary in Heya.
13
-
14
- Email automation becomes startlingly simple when your application framework *is* your automation tool.
15
-
16
- ## Who is Heya for?
17
- - SaaS developers who are marketers at heart
18
- - SaaS marketers who are developers at heart
19
- - Development and marketing teams who work closely together
20
-
21
- ## Stuff we believe
22
- - You should avoid duplicating customer data
23
- - Segments should live as close to home as possible
24
- - So should automation
25
- - So should content
26
- - Code is for everyone, not just developers
27
- - Heya is the best way to engage your users
6
+ Heya is a campaign mailer for Rails. Think of it like ActionMailer, but for timed email sequences. It can also perform other actions like sending a text message.
28
7
 
29
8
  ## Getting started
30
9
  Getting started with Heya is easy:
@@ -21,5 +21,17 @@ module Heya
21
21
  template_name: step.name.underscore
22
22
  )
23
23
  end
24
+
25
+ protected
26
+
27
+ def _prefixes
28
+ @_prefixes_with_campaign_path ||= begin
29
+ if params.is_a?(Hash) && (campaign_name = params[:step]&.campaign&.name&.underscore)
30
+ super | ["heya/campaign_mailer/#{campaign_name}"]
31
+ else
32
+ super
33
+ end
34
+ end
35
+ end
24
36
  end
25
37
  end
@@ -3,6 +3,7 @@
3
3
  require "heya/version"
4
4
  require "heya/engine"
5
5
  require "heya/config"
6
+ require "heya/license"
6
7
  require "heya/campaigns/action"
7
8
  require "heya/campaigns/actions/email"
8
9
  require "heya/campaigns/actions/block"
@@ -45,4 +46,45 @@ module Heya
45
46
  return user.send(segment) if segment.is_a?(Symbol)
46
47
  segment.call(user)
47
48
  end
49
+
50
+ def verify_license!
51
+ unless File.file?(config.license_file)
52
+ puts(<<-NOTICE.strip_heredoc)
53
+ This copy of Heya is licensed for non-commercial non-profit, or 30-day trial usage only.
54
+ For a commercial use license, please visit https://www.heya.email
55
+ NOTICE
56
+ return
57
+ end
58
+
59
+ begin
60
+ license = License.import(File.read(config.license_file))
61
+ rescue License::ImportError
62
+ warn(<<-NOTICE.strip_heredoc)
63
+ Your Heya license is invalid.
64
+ If you need support, please visit https://www.heya.email
65
+ NOTICE
66
+ return
67
+ end
68
+
69
+ if license.expired?
70
+ warn(<<-NOTICE.strip_heredoc)
71
+ Your Heya license has expired.
72
+ To update your license, please visit https://www.heya.email
73
+ NOTICE
74
+ return
75
+ end
76
+
77
+ if (max_user_count = license.restrictions[:user_count]&.to_i)
78
+ user_count = config.user_type.constantize.count
79
+ if user_count > max_user_count
80
+ warn(<<-NOTICE.strip_heredoc)
81
+ Your app exceeds the number of users for your Heya license.
82
+ To upgrade your license, please visit https://www.heya.email
83
+ NOTICE
84
+ end
85
+ return # rubocop:disable Style/RedundantReturn
86
+ end
87
+
88
+ # Valid license
89
+ end
48
90
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/descendants_tracker"
4
+ require "active_support/rescuable"
4
5
 
5
6
  module Heya
6
7
  module Campaigns
@@ -11,6 +12,7 @@ module Heya
11
12
 
12
13
  include Singleton
13
14
  include GlobalID::Identification
15
+ include ActiveSupport::Rescuable
14
16
 
15
17
  def initialize
16
18
  self.steps = []
@@ -27,11 +29,21 @@ module Heya
27
29
  def add(user, restart: false, concurrent: false, send_now: true)
28
30
  return false unless Heya.in_segments?(user, *__segments)
29
31
 
30
- restart && CampaignReceipt
31
- .where(user: user, step_gid: steps.map(&:gid))
32
- .delete_all
32
+ membership = CampaignMembership.where(user: user, campaign_gid: gid)
33
+ if membership.exists?
34
+ return false unless restart
35
+ membership.delete_all
36
+ end
37
+
38
+ if restart
39
+ CampaignReceipt
40
+ .where(user: user, step_gid: steps.map(&:gid))
41
+ .delete_all
42
+ end
33
43
 
34
- CampaignMembership.where(user: user, campaign_gid: gid, concurrent: concurrent).first_or_create!
44
+ membership.create! do |m|
45
+ m.concurrent = concurrent
46
+ end
35
47
 
36
48
  if send_now && (step = steps.first) && step.wait <= 0
37
49
  Scheduler.process(self, step, user)
@@ -61,6 +73,10 @@ module Heya
61
73
  @user_class ||= self.class.user_type.constantize
62
74
  end
63
75
 
76
+ def handle_exception(exception)
77
+ rescue_with_handler(exception) || raise(exception)
78
+ end
79
+
64
80
  attr_accessor :steps
65
81
 
66
82
  private
@@ -89,11 +105,7 @@ module Heya
89
105
  instance
90
106
  end
91
107
 
92
- def handle_exception(exception)
93
- raise exception
94
- end
95
-
96
- delegate :steps, :add, :remove, :users, :gid, :user_class, to: :instance
108
+ delegate :steps, :add, :remove, :users, :gid, :user_class, :handle_exception, to: :instance
97
109
 
98
110
  def default(**params)
99
111
  self.__defaults = __defaults.merge(params).freeze
@@ -6,6 +6,7 @@ module Heya
6
6
  class Config < OpenStruct
7
7
  def initialize
8
8
  super(
9
+ license_file: nil,
9
10
  user_type: "User",
10
11
  campaigns: OpenStruct.new(
11
12
  priority: [],
@@ -15,5 +15,16 @@ module Heya
15
15
  require_dependency(c)
16
16
  end
17
17
  end
18
+
19
+ config.after_initialize do
20
+ license_key = File.expand_path("../../../license_key.pub", __FILE__)
21
+ License.encryption_key = File.read(license_key) if File.file?(license_key)
22
+
23
+ Heya.configure do |config|
24
+ config.license_file ||= Rails.root.join("config/Heya.heya-license")
25
+ end
26
+
27
+ Heya.verify_license!
28
+ end
18
29
  end
19
30
  end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2015 GitLab B.V.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ require "openssl"
26
+ require "date"
27
+ require "json"
28
+ require "base64"
29
+
30
+ require "heya/license/encryptor"
31
+ require "heya/license/boundary"
32
+
33
+ module Heya
34
+ class License
35
+ class Error < StandardError; end
36
+ class ImportError < Error; end
37
+ class ValidationError < Error; end
38
+
39
+ class << self
40
+ attr_reader :encryption_key
41
+ @encryption_key = nil
42
+
43
+ def encryption_key=(key)
44
+ key = OpenSSL::PKey::RSA.new(key.to_s) unless key&.is_a?(OpenSSL::PKey::RSA)
45
+ @encryption_key = key
46
+ @encryptor = nil
47
+ end
48
+
49
+ def encryptor
50
+ @encryptor ||= Encryptor.new(encryption_key)
51
+ end
52
+
53
+ def import(data)
54
+ if data.nil?
55
+ raise ImportError, "No license data."
56
+ end
57
+
58
+ data = Boundary.remove_boundary(data)
59
+
60
+ begin
61
+ license_json = encryptor.decrypt(data)
62
+ rescue Encryptor::Error
63
+ raise ImportError, "License data could not be decrypted."
64
+ end
65
+
66
+ begin
67
+ attributes = JSON.parse(license_json)
68
+ rescue JSON::ParseError
69
+ raise ImportError, "License data is invalid JSON."
70
+ end
71
+
72
+ new(attributes)
73
+ end
74
+ end
75
+
76
+ attr_reader :version
77
+ attr_accessor :licensee, :starts_at, :expires_at
78
+ attr_accessor :restrictions
79
+
80
+ def initialize(attributes = {})
81
+ load_attributes(attributes)
82
+ end
83
+
84
+ def valid?
85
+ return false if !licensee || !licensee.is_a?(Hash) || licensee.length == 0
86
+ return false if !starts_at || !starts_at.is_a?(Date)
87
+ return false if expires_at && !expires_at.is_a?(Date)
88
+ return false if restrictions && !restrictions.is_a?(Hash)
89
+
90
+ true
91
+ end
92
+
93
+ def validate!
94
+ raise ValidationError, "License is invalid" unless valid?
95
+ end
96
+
97
+ def will_expire?
98
+ expires_at
99
+ end
100
+
101
+ def expired?
102
+ will_expire? && Date.today >= expires_at
103
+ end
104
+
105
+ def restricted?(key = nil)
106
+ if key
107
+ restricted? && restrictions.has_key?(key)
108
+ else
109
+ restrictions && restrictions.length >= 1
110
+ end
111
+ end
112
+
113
+ def attributes
114
+ hash = {}
115
+
116
+ hash["version"] = version
117
+ hash["licensee"] = licensee
118
+
119
+ hash["starts_at"] = starts_at
120
+ hash["expires_at"] = expires_at if will_expire?
121
+
122
+ hash["restrictions"] = restrictions if restricted?
123
+
124
+ hash
125
+ end
126
+
127
+ def to_json
128
+ JSON.dump(attributes)
129
+ end
130
+
131
+ def export(boundary: nil)
132
+ validate!
133
+
134
+ data = self.class.encryptor.encrypt(to_json)
135
+
136
+ if boundary
137
+ data = Boundary.add_boundary(data, boundary)
138
+ end
139
+
140
+ data
141
+ end
142
+
143
+ private
144
+
145
+ def load_attributes(attributes)
146
+ attributes = Hash[attributes.map { |k, v| [k.to_s, v] }]
147
+
148
+ version = attributes["version"] || 1
149
+ unless version && version == 1
150
+ raise ArgumentError, "Version is too new"
151
+ end
152
+
153
+ @version = version
154
+
155
+ @licensee = attributes["licensee"]
156
+
157
+ %w[starts_at expires_at].each do |attr|
158
+ value = attributes[attr]
159
+ if value.is_a?(String)
160
+ value = begin
161
+ Date.parse(value)
162
+ rescue
163
+ nil
164
+ end
165
+ end
166
+
167
+ next unless value
168
+
169
+ send("#{attr}=", value)
170
+ end
171
+
172
+ restrictions = attributes["restrictions"]
173
+ if restrictions&.is_a?(Hash)
174
+ restrictions = Hash[restrictions.map { |k, v| [k.to_sym, v] }]
175
+ @restrictions = restrictions
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2015 GitLab B.V.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ module Heya
26
+ class License
27
+ module Boundary
28
+ BOUNDARY_START = /(\A|\r?\n)-*BEGIN .+? LICENSE-*\r?\n/.freeze
29
+ BOUNDARY_END = /\r?\n-*END .+? LICENSE-*(\r?\n|\z)/.freeze
30
+
31
+ class << self
32
+ def add_boundary(data, product_name)
33
+ data = remove_boundary(data)
34
+
35
+ product_name.upcase!
36
+
37
+ pad = lambda do |message, width|
38
+ total_padding = [width - message.length, 0].max
39
+
40
+ padding = total_padding / 2.0
41
+ [
42
+ "-" * padding.ceil,
43
+ message,
44
+ "-" * padding.floor
45
+ ].join
46
+ end
47
+
48
+ [
49
+ pad.call("BEGIN #{product_name} LICENSE", 60),
50
+ data.strip,
51
+ pad.call("END #{product_name} LICENSE", 60)
52
+ ].join("\n")
53
+ end
54
+
55
+ def remove_boundary(data)
56
+ after_boundary = data.split(BOUNDARY_START).last
57
+ in_boundary = after_boundary.split(BOUNDARY_END).first
58
+
59
+ in_boundary
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2015 GitLab B.V.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ module Heya
26
+ class License
27
+ class Encryptor
28
+ class Error < StandardError; end
29
+ class KeyError < Error; end
30
+ class DecryptionError < Error; end
31
+
32
+ attr_accessor :key
33
+
34
+ def initialize(key)
35
+ if key && !key.is_a?(OpenSSL::PKey::RSA)
36
+ raise KeyError, "No RSA encryption key provided."
37
+ end
38
+
39
+ @key = key
40
+ end
41
+
42
+ def encrypt(data)
43
+ unless key.private?
44
+ raise KeyError, "Provided key is not a private key."
45
+ end
46
+
47
+ # Encrypt the data using symmetric AES encryption.
48
+ cipher = OpenSSL::Cipher::AES128.new(:CBC)
49
+ cipher.encrypt
50
+ aes_key = cipher.random_key
51
+ aes_iv = cipher.random_iv
52
+
53
+ encrypted_data = cipher.update(data) + cipher.final
54
+
55
+ # Encrypt the AES key using asymmetric RSA encryption.
56
+ encrypted_key = key.private_encrypt(aes_key)
57
+
58
+ encryption_data = {
59
+ "data" => Base64.encode64(encrypted_data),
60
+ "key" => Base64.encode64(encrypted_key),
61
+ "iv" => Base64.encode64(aes_iv)
62
+ }
63
+
64
+ json_data = JSON.dump(encryption_data)
65
+ Base64.encode64(json_data)
66
+ end
67
+
68
+ def decrypt(data)
69
+ unless key.public?
70
+ raise KeyError, "Provided key is not a public key."
71
+ end
72
+
73
+ json_data = Base64.decode64(data.chomp)
74
+
75
+ begin
76
+ encryption_data = JSON.parse(json_data)
77
+ rescue JSON::ParserError
78
+ raise DecryptionError, "Encryption data is invalid JSON."
79
+ end
80
+
81
+ unless %w[data key iv].all? { |key| encryption_data[key] }
82
+ raise DecryptionError, "Required field missing from encryption data."
83
+ end
84
+
85
+ encrypted_data = Base64.decode64(encryption_data["data"])
86
+ encrypted_key = Base64.decode64(encryption_data["key"])
87
+ aes_iv = Base64.decode64(encryption_data["iv"])
88
+
89
+ begin
90
+ # Decrypt the AES key using asymmetric RSA encryption.
91
+ aes_key = self.key.public_decrypt(encrypted_key)
92
+ rescue OpenSSL::PKey::RSAError
93
+ raise DecryptionError, "AES encryption key could not be decrypted."
94
+ end
95
+
96
+ # Decrypt the data using symmetric AES encryption.
97
+ cipher = OpenSSL::Cipher::AES128.new(:CBC)
98
+ cipher.decrypt
99
+
100
+ begin
101
+ cipher.key = aes_key
102
+ rescue OpenSSL::Cipher::CipherError
103
+ raise DecryptionError, "AES encryption key is invalid."
104
+ end
105
+
106
+ begin
107
+ cipher.iv = aes_iv
108
+ rescue OpenSSL::Cipher::CipherError
109
+ raise DecryptionError, "AES IV is invalid."
110
+ end
111
+
112
+ begin
113
+ data = cipher.update(encrypted_data) + cipher.final
114
+ rescue OpenSSL::Cipher::CipherError
115
+ raise DecryptionError, "Data could not be decrypted."
116
+ end
117
+
118
+ data
119
+ end
120
+ end
121
+ end
122
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Heya
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -0,0 +1,9 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAycgMy1EVcD50WlDhfMDq
3
+ 0wvLZb1iF1Hes5IU37QZeswq4qy5MZKBx8669Jy04QH3RnrY0XyO6c1bnr2rnv8M
4
+ NZL8M0ibGpG0NWv0O2tzaVb7706Vm/VuQGR9BuFSe8ZlKRyvMJpk1Kl8NKeRl+iu
5
+ KMN7AK48/b7/stB8P5NVb/8LCOUfIkcOZcTZN9YJvXbyq5i/i2i2IRgxib0zmkU3
6
+ yCOVZnvW0spaH+Z6SuXTZ/wefXM9XRCpshuEvBnS8vihcyQioFkswF2An4FL8B+N
7
+ AWaeA3NcNJEiUFsCpp0uUOVqVZ2avhpATB7fAG4Qh3JauajhWBrqSJYZn2W6uyDp
8
+ fQIDAQAB
9
+ -----END PUBLIC KEY-----
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heya
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Wood
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-20 00:00:00.000000000 Z
11
+ date: 2020-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -108,8 +108,12 @@ files:
108
108
  - lib/heya/campaigns/step_action_job.rb
109
109
  - lib/heya/config.rb
110
110
  - lib/heya/engine.rb
111
+ - lib/heya/license.rb
112
+ - lib/heya/license/boundary.rb
113
+ - lib/heya/license/encryptor.rb
111
114
  - lib/heya/version.rb
112
115
  - lib/tasks/heya_tasks.rake
116
+ - license_key.pub
113
117
  homepage: https://github.com/honeybadger-io/heya
114
118
  licenses:
115
119
  - Prosperity Public License
@@ -129,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
133
  - !ruby/object:Gem::Version
130
134
  version: '0'
131
135
  requirements: []
132
- rubygems_version: 3.0.3
136
+ rubygems_version: 3.1.2
133
137
  signing_key:
134
138
  specification_version: 4
135
139
  summary: "Heya \U0001F44B"