hotsock 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a3026550ba5036d6d78821dbe5d6f29569010045c9f9a403b5ce8db2448660c4
4
+ data.tar.gz: 505bafd95714b446d7b22a3da85e72557cf260f3634138987afcc0f6d7a30228
5
+ SHA512:
6
+ metadata.gz: c4105017dbd390baeb1aec397bd3684a0fc3676dc038a2b6874344f71f72435029882fd70ab2b3aa7084c7f86779b57187e7ba1bbc370f712df905e3e80f11d3
7
+ data.tar.gz: ba8f049b01a3f045663b25bccb6fdfd408789495e5f0fb626535c25adfef33f13b7bc22c9c520ce9e899feb4ffc218f5fecc4fd6d877ceda61af45a73a610178
data/.standard.yml ADDED
@@ -0,0 +1 @@
1
+ ruby_version: 3.1
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem "rake"
7
+ gem "standard", require: false
8
+ end
9
+
10
+ group :test do
11
+ gem "mocktail"
12
+ gem "tldr"
13
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) JK Tech, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,238 @@
1
+ # Hotsock Ruby Library
2
+
3
+ The Hotsock Ruby library provides convenient access to [Hotsock](https://www.hotsock.io) message publishing APIs and JWT signing from applications written in Ruby.
4
+
5
+ ## Installation
6
+
7
+ You can install the gem with:
8
+
9
+ ```sh
10
+ gem install hotsock
11
+ ```
12
+
13
+ ### Requirements
14
+
15
+ - Ruby 3.1+.
16
+
17
+ ### Bundler
18
+
19
+ ```ruby
20
+ source "https://rubygems.org"
21
+
22
+ gem "hotsock"
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ The library needs to be configured with information specific to your Hotsock installation.
28
+
29
+ ```ruby
30
+ require "hotsock"
31
+
32
+ # Setup the default configuration
33
+ Hotsock.configure do |config|
34
+ config.publish_function_arn = "..."
35
+ config.aws_region = "us-east-1"
36
+ # ... see below for all `configure` options
37
+ end
38
+
39
+ # Publish a message
40
+ Hotsock.publish_message(
41
+ channel: "user.1",
42
+ event: "user.updated",
43
+ data: user.attributes
44
+ # ... see below for all `publish_message` options
45
+ )
46
+
47
+ # Issue a JWT. `issue_token` takes an options hash of claims that will be
48
+ # included in the token payload.
49
+ token = Hotsock.issue_token(
50
+ channels: {
51
+ "user.#{current_user.id}": {
52
+ subscribe: true
53
+ }
54
+ },
55
+ exp: Time.now.to_i + 30,
56
+ iat: Time.now.to_i,
57
+ scope: "connect",
58
+ uid: current_user.id.to_s,
59
+ umd: current_user.metadata_hash
60
+ )
61
+ # => "eyJ0eXAiOiJKV1QiLCJraWQiOiI5NTYxNmI3MCIsI..."
62
+ ```
63
+
64
+ ### Multiple configurations
65
+
66
+ For apps that need to use multiple configurations during the lifetime of a process, like when interacting with multiple Hotsock installations, it's also possible to configure any number of publishers or issuers.
67
+
68
+ ```ruby
69
+ require "hotsock"
70
+
71
+ eastConfig = Hotsock::Config.new
72
+ eastConfig.aws_region = "us-east-1"
73
+ eastConfig.publish_function_arn = "arn:aws:lambda:us-east-1:111111111111:function:Hotsock-Publishing-J718-PublishFunction-t8ix"
74
+
75
+ westConfig = Hotsock::Config.new
76
+ westConfig.aws_region = "us-west-2"
77
+ westConfig.publish_function_arn = "arn:aws:lambda:us-west-2:111111111111:function:Hotsock-Publishing-UUA5-PublishFunction-f5h8"
78
+
79
+ eastPublisher = Hotsock::Publisher.new(eastConfig)
80
+ eastPublisher.publish_message(...)
81
+
82
+ westPublisher = Hotsock::Publisher.new(westConfig)
83
+ westPublisher.publish_message(...)
84
+ ```
85
+
86
+ It's safe (and recommended) to use a single instance of `Hotsock::Publisher` or `Hotsock::Issuer` across threads. Do not create a publisher for each message or an issuer for each token. Doing so will cause performance issues when obtaining AWS credentials. It will also slow down token issuing because the private key will need to be loaded for each token.
87
+
88
+ ### `configure`
89
+
90
+ You typically call `configure` once when your application is starting up. If using Rails, place your call to `configure` in an initializer.
91
+
92
+ ```ruby
93
+ require "hotsock"
94
+
95
+ Hotsock.configure do |config|
96
+ # The Amazon Resource Name (Arn) of the Lambda function used to publish
97
+ # Hotsock messages. Grab the value from `PublishFunctionArn` in your
98
+ # installation's CloudFormation stack output. (required)
99
+ config.publish_function_arn = "arn:aws:lambda:us-east-1:111111111111:function:Hotsock-Publishing-J718-PublishFunction-t8ix"
100
+
101
+ # The AWS region where your Hotsock installation resides. (required)
102
+ config.aws_region = "us-east-1"
103
+
104
+ # If using static IAM user credentials to authorize access to invoke the
105
+ # message publishing Lambda function, specify the user's Access Key ID and
106
+ # Secret Access Key. (optional)
107
+ config.aws_access_key_id = "AKIAIOSFODNN7EXAMPLE"
108
+ config.aws_secret_access_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
109
+
110
+ # If the IAM principal (user or role) that you are authorizing as must assume
111
+ # another role to publish messages to the Lambda function, specify the role
112
+ # that must be assumed. (optional)
113
+ config.aws_assume_role_arn = "arn:aws:iam::111111111111:role/MyRoleToAssume"
114
+
115
+ # If specifying `aws_assume_role_arn`, you can specify a session name. If
116
+ # unspecified and assuming a role, this will be set to
117
+ # "hotsock-ruby-#{Hotsock::VERSION}"
118
+ # (optional)
119
+ config.aws_assume_role_session_name = "my-application-name"
120
+
121
+ # If required by your administrator when assuming a role, specify an
122
+ # External ID. (optional)
123
+ config.aws_assume_role_external_id = "6f4c10321f"
124
+
125
+ # If using this library for signing tokens, this is the private key.
126
+ # Committing this key to source control is not recommended. Instead consider
127
+ # using environment variables, Rails encrypted credentials, AWS Parameter
128
+ # Store, etc. and loading this key from there. For ES256 (ECDSA using P-256
129
+ # and SHA-256), this key must be in PEM format. Don't use the key below!
130
+ # Generate your own! (optional)
131
+ config.issuer_private_key = "-----BEGIN EC PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg72ab3fXPvtD2iIQQ\n/RWiZh8WA6T9u6JNhEuy1DPSFpuhRANCAASmEDhCts7/LkmooXH1tMhyh9Qn94e3\ny3e/UtmnnAYMPwro8iySvqEUrYaDUqQ3iMjYpf+mvxOFmCy97MsBj/pu\n-----END EC PRIVATE KEY-----"
132
+
133
+ # The algorithm to use when signing with the above key. Defaults to ES256.
134
+ # Supports HS256, HS384, HS512, ES256, ES384, ES512, RS256, RS384, RS512.
135
+ config.issuer_key_algorithm = "ES256"
136
+
137
+ # Sets the `kid` JWT header to this value for all issued tokens. (optional)
138
+ config.issuer_key_id = "95616b70"
139
+
140
+ # Sets the default value of the `aud` JWT payload claim to this value for
141
+ # issued tokens. Override by setting `aud` in the claims hash passed to
142
+ # `issue_token`. Ensure this matches the required audience claim required by
143
+ # your Hotsock installation configuration. (optional)
144
+ config.issuer_aud_claim = "hotsock"
145
+
146
+ # Sets the default value of the `iat` JWT payload claim to the timestamp when
147
+ # the token is generated. Override by setting `iat` in the claims hash passed
148
+ # to `issue_token`. (optional, false by default)
149
+ config.issuer_iat_claim = true
150
+
151
+ # Sets the default value of the `iss` JWT payload claim to this value for
152
+ # issued tokens. Override by setting `iss` in the claims hash passed to
153
+ # `issue_token`. (optional)
154
+ config.issuer_iss_claim = "my-application-name"
155
+
156
+ # Sets the default value of the `jti` JWT payload claim to a unique ID (UUID)
157
+ # when the token is generated. Override by setting `jti` in the claims hash
158
+ # passed to `issue_token`. (optional, false by default)
159
+ config.issuer_jti_claim = true
160
+
161
+ # Sets the default value of the `exp` JWT payload claim to this many seconds
162
+ # from the time that the token was issued. Override by setting `exp` in the
163
+ # claims hash passed to `issue_token`. (optional)
164
+ config.issuer_token_ttl = 10
165
+ end
166
+ ```
167
+
168
+ ### `Hotsock.publish_message` or `Hotsock::Publisher#publish_message`
169
+
170
+ The `publish_message` method directly invokes the AWS Lambda function specified in `config.publish_function_arn`. Supported attributes are [documented here](https://www.hotsock.io/docs/server-api/publish-messages).
171
+
172
+ `publish_message` returns the raw `Aws::Lambda::Types::InvocationResponse` struct. The reason for this is because the actual response body is rarely needed - parsing the JSON and returning another object for each message would consume unnecessary cycles in the majority of cases.
173
+
174
+ A case where you may want the response is when `eager_id_generation` is `true`. In this case you can access the payload like the following. This can obviously be shortened in a real application, but is illustrated in multiple steps here to clarify how it works.
175
+
176
+ ```ruby
177
+ lambda_response = Hotsock.publish_message(channel: "mychannel", event: "myevent", eager_id_generation: true)
178
+ # => #<struct Aws::Lambda::Types::InvocationResponse
179
+ # status_code=200,
180
+ # function_error=nil,
181
+ # log_result=nil,
182
+ # payload=#<StringIO:0x000000010af76290>,
183
+ # executed_version="$LATEST">
184
+ hotsock_response = lambda_response.payload.read
185
+ # => "{\"id\":\"01HBM6KJCPNZK11H79ZSHGAEE9\",\"channel\":\"mychannel\",\"event\":\"myevent\"}"
186
+ message_id = JSON.load(response)["id"]
187
+ # => "01HBM6KJCPNZK11H79ZSHGAEE9"
188
+ ```
189
+
190
+ ### `Hotsock.issue_token` or `Hotsock::Issuer#issue_token`
191
+
192
+ The `issue_token` method locally signs and returns a JSON Web Token (JWT) using the key specified in `config.issuer_private_key`. It takes a single argument with a `Hash` of payload claims. This can be used to issue a JWT for anything, but provides some configuration options with Hotsock in mind. Hotsock-supported token claims are [documented here](https://www.hotsock.io/docs/connection/claims).
193
+
194
+ At a minimum, Hotsock requires an `exp` claim to produce a valid token. Here's an example issuing a token that is valid for 30 seconds. You'll likely want additional claims.
195
+
196
+ ```ruby
197
+ Hotsock.issue_token(exp: Time.now.to_i + 30, scope: "connect")
198
+ # => "eyJ0eXAiOiJKV1QiLCJraWQiOiI5NTYxNmI3MCIsImFsZyI6IkhTMjU2In0.eyJleHAiOjE2OTYxMTcwNTIsInNjb3BlIjoiY29ubmVjdCJ9.CRam2nIGu55tIGRdXmU2rBpg2IVWzrBRmroSVquhg5I"
199
+ ```
200
+
201
+ This translates to the following decoded token.
202
+
203
+ ```json
204
+ {
205
+ "typ": "JWT",
206
+ "kid": "95616b70",
207
+ "alg": "ES256"
208
+ }
209
+ {
210
+ "exp": 1696117052,
211
+ "scope": "connect"
212
+ }
213
+ ```
214
+
215
+ ## AWS Permissions
216
+
217
+ If your application is running on EC2, ECS, Lambda, or another service that provides a built-in role (recommended), there is no need to specify credentials when calling `Hotsock.configure`. They will be loaded and refreshed automatically from the instance, task, or function role.
218
+
219
+ Regardless of the AWS principal type, this role or user must be granted `lambda:InvokeFunction` permission to publish messages to the Hotsock publisher Lambda function. The policy might look something like this (replace the example function Arn with your `PublishFunctionArn`) and attach the policy to your role or user:
220
+
221
+ ```json
222
+ {
223
+ "Version": "2012-10-17",
224
+ "Statement": [
225
+ {
226
+ "Action": ["lambda:InvokeFunction"],
227
+ "Effect": "Allow",
228
+ "Resource": [
229
+ "arn:aws:lambda:us-east-1:111111111111:function:Hotsock-Publishing-J718-PublishFunction-t8ix"
230
+ ]
231
+ }
232
+ ]
233
+ }
234
+ ```
235
+
236
+ ## License
237
+
238
+ See [LICENSE](LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require "standard/rake"
3
+ require "tldr/rake"
4
+
5
+ task default: [:tldr, "standard:fix"]
data/hotsock.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift(::File.join(::File.dirname(__FILE__), "lib"))
4
+
5
+ require "hotsock/version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "hotsock"
9
+ spec.version = Hotsock::VERSION
10
+ spec.authors = ["James Miller"]
11
+ spec.email = ["support@hotsock.io"]
12
+ spec.homepage = "https://www.hotsock.io"
13
+ spec.summary = "Ruby bindings for the Hotsock message publishing APIs and JWT signing"
14
+ spec.description = "Hotsock is a real-time WebSockets service for your web and mobile applications, fully-managed and self-hosted in your AWS account."
15
+ spec.license = "MIT"
16
+ spec.required_ruby_version = ">= 3.1"
17
+
18
+ ignored = Regexp.union(
19
+ /\A\.git/,
20
+ /\Atest/
21
+ )
22
+ spec.files = `git ls-files`.split("\n").reject { |f| ignored.match(f) }
23
+
24
+ spec.add_dependency "jwt", "~> 2.7"
25
+ spec.add_dependency "aws-sdk-lambda", "~> 1.105"
26
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ module Hotsock
6
+ class Config
7
+ def aws_region
8
+ @aws_region or raise ArgumentError, "Hotsock configuration requires an aws_region"
9
+ end
10
+ attr_writer :aws_region
11
+
12
+ attr_accessor :aws_access_key_id
13
+ attr_accessor :aws_secret_access_key
14
+ attr_accessor :aws_assume_role_arn
15
+ attr_accessor :aws_assume_role_session_name
16
+ attr_accessor :aws_assume_role_external_id
17
+ attr_accessor :publish_function_arn
18
+ attr_accessor :issuer_aud_claim
19
+ attr_accessor :issuer_iat_claim
20
+ attr_accessor :issuer_iss_claim
21
+ attr_accessor :issuer_jti_claim
22
+ attr_accessor :issuer_token_ttl
23
+ attr_accessor :issuer_key_id
24
+
25
+ def issuer_private_key
26
+ @issuer_private_key or raise ArgumentError, "Hotsock configuration requires issuer_private_key for JWT issuing"
27
+ end
28
+ attr_writer :issuer_private_key
29
+
30
+ def issuer_key_algorithm
31
+ @issuer_key_algorithm || "ES256"
32
+ end
33
+ attr_writer :issuer_key_algorithm
34
+
35
+ def issuer_key
36
+ case issuer_key_algorithm
37
+ when "HS256", "HS384", "HS512"
38
+ @issuer_key ||= issuer_private_key
39
+ when "RS256", "RS384", "RS512"
40
+ @issuer_key ||= OpenSSL::PKey::RSA.new(issuer_private_key)
41
+ when "ES256", "ES384", "ES512"
42
+ @issuer_key ||= OpenSSL::PKey::EC.new(issuer_private_key)
43
+ else
44
+ raise ArgumentError, "Issuer key algorithm must be one of HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jwt"
4
+ require "securerandom"
5
+
6
+ module Hotsock
7
+ class Issuer
8
+ def initialize(config)
9
+ @config = config
10
+ end
11
+
12
+ def issue_token(claims = {})
13
+ headers = {typ: "JWT"}
14
+ if @config.issuer_key_id
15
+ headers[:kid] = @config.issuer_key_id
16
+ end
17
+
18
+ payload = {}
19
+ now_i = Time.now.to_i
20
+ if @config.issuer_aud_claim
21
+ payload[:aud] = @config.issuer_aud_claim
22
+ end
23
+ if @config.issuer_iat_claim == true
24
+ payload[:iat] = now_i
25
+ end
26
+ if @config.issuer_iss_claim
27
+ payload[:iss] = @config.issuer_iss_claim
28
+ end
29
+ if @config.issuer_jti_claim == true
30
+ payload[:jti] = SecureRandom.uuid
31
+ end
32
+ if @config.issuer_token_ttl.to_i > 0
33
+ payload[:exp] = now_i + @config.issuer_token_ttl.to_i
34
+ end
35
+
36
+ JWT.encode(payload.merge(claims), @config.issuer_key, @config.issuer_key_algorithm, headers)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "aws-sdk-lambda"
5
+ require "aws-sdk-sts"
6
+
7
+ module Hotsock
8
+ class Publisher
9
+ def initialize(config)
10
+ @config = config
11
+ end
12
+
13
+ def publish_message(channel:, event:, **options)
14
+ payload = {event:, channel:}
15
+ payload[:data] = options.delete(:data) if options[:data]
16
+ payload[:deduplicationId] = options.delete(:deduplication_id) if options[:deduplication_id]
17
+ payload[:eagerIdGeneration] = options.delete(:eager_id_generation) if options[:eager_id_generation]
18
+ payload[:emitPubSubEvent] = options.delete(:emit_pub_sub_event) if options[:emit_pub_sub_event]
19
+ options.each do |k, v|
20
+ payload[k] = v
21
+ end
22
+
23
+ lambda_client.invoke(
24
+ function_name: @config.publish_function_arn,
25
+ payload: JSON.dump(payload)
26
+ )
27
+ end
28
+
29
+ private
30
+
31
+ def lambda_client
32
+ return @lambda_client if @lambda_client
33
+
34
+ options = {region: @config.aws_region}
35
+
36
+ if @config.aws_assume_role_arn
37
+ options[:credentials] = assume_role_credentials
38
+ elsif @config.aws_access_key_id || @config.aws_secret_access_key
39
+ options[:credentials] = static_credentials
40
+ end
41
+
42
+ @lambda_client ||= Aws::Lambda::Client.new(options)
43
+ end
44
+
45
+ def static_credentials
46
+ Aws::Credentials.new(
47
+ @config.aws_access_key_id,
48
+ @config.aws_secret_access_key
49
+ )
50
+ end
51
+
52
+ def assume_role_credentials
53
+ Aws::AssumeRoleCredentials.new(
54
+ client: sts_base_client,
55
+ role_arn: @config.aws_assume_role_arn,
56
+ role_session_name: @config.aws_assume_role_session_name || "hotsock-ruby-#{Hotsock::VERSION}",
57
+ external_id: @config.aws_assume_role_external_id
58
+ )
59
+ end
60
+
61
+ def sts_base_client
62
+ options = {region: @config.aws_region}
63
+
64
+ if @config.aws_access_key_id || @config.aws_secret_access_key
65
+ options[:credentials] = static_credentials
66
+ end
67
+
68
+ Aws::STS::Client.new(options)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hotsock
4
+ VERSION = "1.0.0"
5
+ end
data/lib/hotsock.rb ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hotsock/version"
4
+ require "hotsock/config"
5
+ require "hotsock/issuer"
6
+ require "hotsock/publisher"
7
+
8
+ module Hotsock
9
+ class << self
10
+ def configure(&block)
11
+ yield default_config
12
+ end
13
+
14
+ def publish_message(channel:, event:, **options)
15
+ default_publisher.publish_message(channel:, event:, **options)
16
+ end
17
+
18
+ def issue_token(payload = {})
19
+ default_issuer.issue_token(payload)
20
+ end
21
+
22
+ private
23
+
24
+ def default_config
25
+ @default_config ||= Hotsock::Config.new
26
+ end
27
+
28
+ def default_publisher
29
+ @default_publisher ||= Hotsock::Publisher.new(default_config)
30
+ end
31
+
32
+ def default_issuer
33
+ @default_issuer ||= Hotsock::Issuer.new(default_config)
34
+ end
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hotsock
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - James Miller
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-04-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jwt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk-lambda
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.105'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.105'
41
+ description: Hotsock is a real-time WebSockets service for your web and mobile applications,
42
+ fully-managed and self-hosted in your AWS account.
43
+ email:
44
+ - support@hotsock.io
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".standard.yml"
50
+ - Gemfile
51
+ - LICENSE
52
+ - README.md
53
+ - Rakefile
54
+ - hotsock.gemspec
55
+ - lib/hotsock.rb
56
+ - lib/hotsock/config.rb
57
+ - lib/hotsock/issuer.rb
58
+ - lib/hotsock/publisher.rb
59
+ - lib/hotsock/version.rb
60
+ homepage: https://www.hotsock.io
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '3.1'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 3.3.26
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Ruby bindings for the Hotsock message publishing APIs and JWT signing
83
+ test_files: []