queueit_knownuserv3 3.6.1 → 3.7.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 313b49836c5ca9e7a82484eaf07feb22fda8e02c29d24bfecb3a1b85a3403dad
4
+ data.tar.gz: b1a45a83424b57e4e77ac8d56a73f55941a84578afc8b945c69c56e7b2338a5d
5
+ SHA512:
6
+ metadata.gz: 17f214dff16a75677a943513e3b8bf705f413d8abcb5c6d0d001f5338d42136c04c04fdfc42c77485d3d81e8493354ccb078ae4c7d6633143fd23394991a307a
7
+ data.tar.gz: 2e6e657e9c26e1e5a255dbc9e2fdff3c7530fa2433d10676d76ae3a1c042cde08b7d0aeb3811179cc21ca632665f686170c99a198279a0f99e776fc2cc352129
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in queueit_knownuserv3.gemspec
4
- gemspec
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in queueit_knownuserv3.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Queue-it
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,188 @@
1
+ # KnownUser.V3.RubyOnRails
2
+ Before getting started please read the [documentation](https://github.com/queueit/Documentation/tree/main/serverside-connectors) to get acquainted with server-side connectors.
3
+
4
+ This connector supports Ruby v.1.9.3+ and Rails v.3.2+.
5
+
6
+ ## Installation
7
+ Queue-it KnownUser V3 is distributed as a gem, which is how it should be used in your app.
8
+
9
+ Include the gem in your Gemfile:
10
+
11
+ ```ruby
12
+ gem "queueit_knownuserv3"
13
+ ```
14
+
15
+ You can find the latest released version [here](https://github.com/queueit/KnownUser.V3.RubyOnRails/releases/latest) and distributed
16
+ gem [here](https://rubygems.org/gems/queueit_knownuserv3).
17
+
18
+
19
+ ## Implementation
20
+ If we have the `integrationconfig.json` copied in the rails app folder then
21
+ the following example of a controller is all that is needed to validate that a user has been through the queue:
22
+
23
+ ```ruby
24
+ class ResourceController < ApplicationController
25
+ def index
26
+ begin
27
+
28
+ configJson = File.read('integrationconfig.json')
29
+ customerId = "" # Your Queue-it customer ID
30
+ secretKey = "" # Your 72 char secret key as specified in Go Queue-it self-service platform
31
+
32
+ requestUrl = request.original_url
33
+ pattern = Regexp.new("([\\?&])(" + QueueIt::KnownUser::QUEUEIT_TOKEN_KEY + "=[^&]*)", Regexp::IGNORECASE)
34
+ requestUrlWithoutToken = requestUrl.gsub(pattern, '')
35
+ # The requestUrlWithoutToken is used to match Triggers and as the Target url (where to return the users to).
36
+ # It is therefor important that this is exactly the url of the users browsers. So, if your webserver is
37
+ # behind e.g. a load balancer that modifies the host name or port, reformat requestUrlWithoutToken before proceeding.
38
+ # Example of replacing host from requestUrlWithoutToken
39
+ #requestUriNoToken = URI.parse(requestUrlWithoutToken)
40
+ #requestUriNoToken.host = "INSERT-REPLACEMENT-HOST-HERE"
41
+ #requestUrlWithoutToken = requestUriNoToken.to_s
42
+
43
+ queueitToken = request.query_parameters[QueueIt::KnownUser::QUEUEIT_TOKEN_KEY.to_sym]
44
+
45
+ # Initialize the SDK with the rails http context (must be done before calling validateRequestByIntegrationConfig)
46
+ QueueIt::HttpContextProvider::setHttpContext(QueueIt::RailsHttpContext.new(request))
47
+
48
+ # Verify if the user has been through the queue
49
+ validationResult = QueueIt::KnownUser.validateRequestByIntegrationConfig(
50
+ requestUrlWithoutToken,
51
+ queueitToken,
52
+ configJson,
53
+ customerId,
54
+ secretKey)
55
+
56
+ if(validationResult.doRedirect)
57
+ #Adding no cache headers to prevent browsers to cache requests
58
+ response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate, max-age=0"
59
+ response.headers["Pragma"] = "no-cache"
60
+ response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
61
+ #end
62
+
63
+ if(!validationResult.isAjaxResult)
64
+ # Send the user to the queue - either becuase hash was missing or becuase is was invalid
65
+ redirect_to validationResult.redirectUrl
66
+ else
67
+ head :ok
68
+ ajaxQueueRedirectHeaderName = validationResult.getAjaxQueueRedirectHeaderKey()
69
+ response.headers[ajaxQueueRedirectHeaderName] = validationResult.getAjaxRedirectUrl()
70
+ response.headers["Access-Control-Expose-Headers"] = ajaxQueueRedirectHeaderName
71
+ end
72
+ else
73
+ # Request can continue, we remove queueittoken from url to avoid sharing of user specific token
74
+ if(requestUrl != requestUrlWithoutToken && validationResult.actionType == "Queue")
75
+ redirect_to requestUrlWithoutToken
76
+ end
77
+ end
78
+
79
+ rescue StandardError => stdErr
80
+ # There was an error validating the request
81
+ # Use your own logging framework to log the error
82
+ # This was a configuration error, so we let the user continue
83
+ puts stdErr.message
84
+ end
85
+ end
86
+ end
87
+ ```
88
+
89
+
90
+ ## Implementation using inline queue configuration
91
+ Specify the configuration in code without using the Trigger/Action paradigm. In this case it is important *only to queue-up page requests* and not requests for resources.
92
+ This can be done by adding custom filtering logic before caling the `QueueIt::KnownUser.resolveQueueRequestByLocalConfig` method.
93
+
94
+ The following is an example of how to specify the configuration in code:
95
+
96
+ ```ruby
97
+ class ResourceController < ApplicationController
98
+ def index
99
+ begin
100
+
101
+ customerId = "" # Your Queue-it customer ID
102
+ secretKey = "" # Your 72 char secret key as specified in Go Queue-it self-service platform
103
+ eventConfig = QueueIt::QueueEventConfig.new
104
+ eventConfig.eventId = "" # ID of the queue to use
105
+ eventConfig.queueDomain = "xxx.queue-it.net" # Domain name of the queue.
106
+ # eventConfig.cookieDomain = ".my-shop.com" # Optional - Domain name where the Queue-it session cookie should be saved
107
+ eventConfig.cookieValidityMinute = 15 # Validity of the Queue-it session cookie should be positive number.
108
+ eventConfig.extendCookieValidity = true # Should the Queue-it session cookie validity time be extended each time the validation runs?
109
+ # eventConfig.culture = "da-DK" # Optional - Culture of the queue layout in the format specified here: https:#msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx. If unspecified then settings from Event will be used.
110
+ # eventConfig.layoutName = "NameOfYourCustomLayout" # Optional - Name of the queue layout. If unspecified then settings from Event will be used.
111
+
112
+ requestUrl = request.original_url
113
+ queueitToken = request.query_parameters[QueueIt::KnownUser::QUEUEIT_TOKEN_KEY.to_sym]
114
+
115
+ # Initialize the SDK with the rails http context (must be done before calling validateRequestByIntegrationConfig)
116
+ QueueIt::HttpContextProvider::setHttpContext(QueueIt::RailsHttpContext.new(request))
117
+
118
+ # Verify if the user has been through the queue
119
+ validationResult = QueueIt::KnownUser.resolveQueueRequestByLocalConfig(
120
+ requestUrl,
121
+ queueitToken,
122
+ eventConfig,
123
+ customerId,
124
+ secretKey)
125
+
126
+ if(validationResult.doRedirect)
127
+ #Adding no cache headers to prevent browsers to cache requests
128
+ response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate, max-age=0"
129
+ response.headers["Pragma"] = "no-cache"
130
+ response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
131
+ #end
132
+ if(!validationResult.isAjaxResult)
133
+ # Send the user to the queue - either becuase hash was missing or becuase is was invalid
134
+ redirect_to validationResult.redirectUrl
135
+ else
136
+ head :ok
137
+ ajaxQueueRedirectHeaderName = validationResult.getAjaxQueueRedirectHeaderKey()
138
+ response.headers[ajaxQueueRedirectHeaderName] = validationResult.getAjaxRedirectUrl()
139
+ response.headers["Access-Control-Expose-Headers"] = ajaxQueueRedirectHeaderName
140
+ end
141
+ else
142
+ # Request can continue - we remove queueittoken form querystring parameter to avoid sharing of user specific token
143
+ pattern = Regexp.new("([\\?&])(" + QueueIt::KnownUser::QUEUEIT_TOKEN_KEY + "=[^&]*)", Regexp::IGNORECASE)
144
+ requestUrlWithoutToken = requestUrl.gsub(pattern, '')
145
+
146
+ if(requestUrl != requestUrlWithoutToken && validationResult.actionType == "Queue")
147
+ redirect_to requestUrlWithoutToken
148
+ end
149
+ end
150
+
151
+ rescue StandardError => stdErr
152
+ # There was an error validating the request
153
+ # Use your own logging framework to log the error
154
+ # This was a configuration error, so we let the user continue
155
+ puts stdErr.message
156
+ end
157
+ end
158
+ end
159
+ ```
160
+
161
+ ## Advanced Features
162
+ ### Request body trigger
163
+
164
+ The connector supports triggering on request body content. An example could be a POST call with specific item ID where you want end-users to queue up for.
165
+ For this to work, you will need to contact Queue-it support or enable request body triggers in your integration settings in your GO Queue-it platform account.
166
+ Once enabled you will need to update your integration so request body is available for the connector.
167
+ You need to create a custom RailsHttpContext similar to this one (make sure to inherit from `QueueIt::RailsHttpContext`):
168
+
169
+ ```ruby
170
+ class RailsHttpContextWithRequestBody < QueueIt::RailsHttpContext
171
+ @request
172
+
173
+ def initialize(request)
174
+ super
175
+ @request = request
176
+ end
177
+
178
+ def requestBodyAsString
179
+ return @request.raw_post
180
+ end
181
+ end
182
+ ```
183
+
184
+ Then, on each request, before calling the any of the SDK methods, you should initialize the SDK with your custom RailsHttpContext implementation, instead of the RailsHttpContext:
185
+
186
+ ```ruby
187
+ QueueIt::HttpContextProvider::setHttpContext(RailsHttpContextWithRequestBody.new(request))
188
+ ```
data/Rakefile CHANGED
@@ -1,2 +1,2 @@
1
- require "bundler/gem_tasks"
2
- task :default => :spec
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console CHANGED
@@ -1,14 +1,14 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "queueit_knownuserv3"
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
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "queueit_knownuserv3"
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
data/bin/setup CHANGED
@@ -1,8 +1,8 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -1,69 +1,69 @@
1
- module QueueIt
2
- class ConnectorDiagnostics
3
- attr_accessor :isEnabled
4
- attr_accessor :hasError
5
- attr_accessor :validationResult
6
-
7
- def initialize
8
- @isEnabled = false
9
- @hasError = false
10
- @validationResult = nil
11
- end
12
-
13
- def setStateWithTokenError(customerId, errorCode)
14
- @hasError = true
15
- @validationResult = RequestValidationResult.new(
16
- "ConnectorDiagnosticsRedirect",
17
- nil, nil,
18
- "https://" + customerId + ".api2.queue-it.net/" + customerId + "/diagnostics/connector/error/?code=" + errorCode,
19
- nil, nil)
20
- end
21
-
22
- def setStateWithSetupError()
23
- @hasError = true
24
- @validationResult = RequestValidationResult.new(
25
- "ConnectorDiagnosticsRedirect",
26
- nil, nil,
27
- "https://api2.queue-it.net/diagnostics/connector/error/?code=setup",
28
- nil, nil)
29
- end
30
-
31
- def self.verify(customerId, secretKey, queueitToken)
32
- diagnostics = ConnectorDiagnostics.new
33
-
34
- qParams = QueueUrlParams.extractQueueParams(queueitToken)
35
-
36
- if(qParams == nil)
37
- return diagnostics
38
- end
39
-
40
- if(qParams.redirectType == nil)
41
- return diagnostics
42
- end
43
-
44
- if(not qParams.redirectType.upcase.eql?("DEBUG"))
45
- return diagnostics
46
- end
47
-
48
- if(Utils.isNilOrEmpty(customerId) or Utils.isNilOrEmpty(secretKey))
49
- diagnostics.setStateWithSetupError()
50
- return diagnostics
51
- end
52
-
53
- calculatedHash = OpenSSL::HMAC.hexdigest('sha256', secretKey, qParams.queueITTokenWithoutHash)
54
- if(not qParams.hashCode.eql?(calculatedHash))
55
- diagnostics.setStateWithTokenError(customerId, "hash")
56
- return diagnostics
57
- end
58
-
59
- if(qParams.timeStamp < Time.now.getutc.tv_sec)
60
- diagnostics.setStateWithTokenError(customerId, "timestamp")
61
- return diagnostics
62
- end
63
-
64
- diagnostics.isEnabled = true
65
-
66
- return diagnostics
67
- end
68
- end
1
+ module QueueIt
2
+ class ConnectorDiagnostics
3
+ attr_accessor :isEnabled
4
+ attr_accessor :hasError
5
+ attr_accessor :validationResult
6
+
7
+ def initialize
8
+ @isEnabled = false
9
+ @hasError = false
10
+ @validationResult = nil
11
+ end
12
+
13
+ def setStateWithTokenError(customerId, errorCode)
14
+ @hasError = true
15
+ @validationResult = RequestValidationResult.new(
16
+ "ConnectorDiagnosticsRedirect",
17
+ nil, nil,
18
+ "https://" + customerId + ".api2.queue-it.net/" + customerId + "/diagnostics/connector/error/?code=" + errorCode,
19
+ nil, nil)
20
+ end
21
+
22
+ def setStateWithSetupError()
23
+ @hasError = true
24
+ @validationResult = RequestValidationResult.new(
25
+ "ConnectorDiagnosticsRedirect",
26
+ nil, nil,
27
+ "https://api2.queue-it.net/diagnostics/connector/error/?code=setup",
28
+ nil, nil)
29
+ end
30
+
31
+ def self.verify(customerId, secretKey, queueitToken)
32
+ diagnostics = ConnectorDiagnostics.new
33
+
34
+ qParams = QueueUrlParams.extractQueueParams(queueitToken)
35
+
36
+ if(qParams == nil)
37
+ return diagnostics
38
+ end
39
+
40
+ if(qParams.redirectType == nil)
41
+ return diagnostics
42
+ end
43
+
44
+ if(not qParams.redirectType.upcase.eql?("DEBUG"))
45
+ return diagnostics
46
+ end
47
+
48
+ if(Utils.isNilOrEmpty(customerId) or Utils.isNilOrEmpty(secretKey))
49
+ diagnostics.setStateWithSetupError()
50
+ return diagnostics
51
+ end
52
+
53
+ calculatedHash = OpenSSL::HMAC.hexdigest('sha256', secretKey, qParams.queueITTokenWithoutHash)
54
+ if(not qParams.hashCode.eql?(calculatedHash))
55
+ diagnostics.setStateWithTokenError(customerId, "hash")
56
+ return diagnostics
57
+ end
58
+
59
+ if(qParams.timeStamp < Time.now.getutc.tv_sec)
60
+ diagnostics.setStateWithTokenError(customerId, "timestamp")
61
+ return diagnostics
62
+ end
63
+
64
+ diagnostics.isEnabled = true
65
+
66
+ return diagnostics
67
+ end
68
+ end
69
69
  end
@@ -0,0 +1,93 @@
1
+ module QueueIt
2
+ class IHttpContext
3
+
4
+ def userAgent
5
+ raise 'userAgent not implemented'
6
+ end
7
+
8
+ def headers
9
+ raise 'headers not implemented'
10
+ end
11
+
12
+ def url
13
+ raise 'url not implemented'
14
+ end
15
+
16
+ def userHostAddress
17
+ raise 'userHostAddress not implemented'
18
+ end
19
+
20
+ def cookieManager
21
+ raise 'cookieManager not implemented'
22
+ end
23
+
24
+ def requestBodyAsString
25
+ raise 'requestBodyAsString not implemented'
26
+ end
27
+
28
+ end
29
+
30
+ class RailsHttpContext < IHttpContext
31
+ @request
32
+
33
+ def initialize(request)
34
+ @request = request
35
+ end
36
+
37
+ def userAgent
38
+ return @request.user_agent
39
+ end
40
+
41
+ def headers
42
+ return @request.headers
43
+ end
44
+
45
+ def url
46
+ return @request.env["rack.url_scheme"] + "://" + @request.env["HTTP_HOST"] + @request.original_fullpath
47
+ end
48
+
49
+ def userHostAddress
50
+ return @request.remote_ip
51
+ end
52
+
53
+ def cookieManager
54
+ cookieManager = CookieManager.new(@request.cookie_jar)
55
+ return cookieManager
56
+ end
57
+
58
+ def requestBodyAsString
59
+ return ''
60
+ end
61
+
62
+ end
63
+
64
+ # Used to initialize SDK for each request
65
+ class SDKInitializer
66
+
67
+ def self.setHttpContext(httpContext)
68
+ if (httpContext.class < IHttpContext)
69
+ HttpContextProvider.setHttpContext(httpContext)
70
+ else
71
+ raise "httpContext must be a subclass of IHttpContext (e.g. MyHttpContext < IHttpContext)"
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ class HttpContextProvider
78
+ @@httpContext
79
+
80
+ def self.httpContext
81
+ if (defined?(@@httpContext))
82
+ return @@httpContext
83
+ else
84
+ raise "Please initialize the SDK using SDKInitializer.setHttpContext(httpContext) method"
85
+ end
86
+ end
87
+
88
+ def self.setHttpContext(httpContext)
89
+ @@httpContext = httpContext
90
+ end
91
+
92
+ end
93
+ end