govuk_personalisation 0.5.0 → 0.6.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +57 -6
- data/lib/govuk_personalisation.rb +3 -5
- data/lib/govuk_personalisation/controller_concern.rb +129 -0
- data/lib/govuk_personalisation/flash.rb +50 -0
- data/lib/govuk_personalisation/test_helpers/features.rb +7 -2
- data/lib/govuk_personalisation/test_helpers/requests.rb +6 -2
- data/lib/govuk_personalisation/version.rb +1 -1
- metadata +4 -3
- data/lib/govuk_personalisation/account_concern.rb +0 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08b691342c4c22592162f9eb11e8c8f74b8fea75af5669568c71d15337166626'
|
4
|
+
data.tar.gz: 0e266ec1d1f91a7537ccef2c1a4398e90b4c0435546772d41877cfd34e9df092
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f265633173eee3b60e436c781ddb4047d849471cc1760d88e8c3e497a79d8a0fd188a4c3908feb33fecf3b8c2b171dbbc1ea7f08ed837fae2d58cfc5658ae35
|
7
|
+
data.tar.gz: d90dc8a74720981e16d7d379939c08072806ead930d012bb40c1a57ac2e90ae3879a10d7fb0bfbe3d874d39c70312952d72c0c9eca452fd757906c253ecb402e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# 0.6.0
|
2
|
+
|
3
|
+
- Add `GovukPersonalisation::Flash` and helper methods to the concern ([#9](https://github.com/alphagov/govuk_personalisation/pull/9))
|
4
|
+
- Ensure every method has RDoc ([#10](https://github.com/alphagov/govuk_personalisation/pull/10))
|
5
|
+
- Remove unused `GovukPersonalisation::Error` class ([#10](https://github.com/alphagov/govuk_personalisation/pull/10))
|
6
|
+
- BREAKING: Rename `GovukPersonalisation::AccountConcern` to `GovukPersonalisation::ControllerConcern` ([#11](https://github.com/alphagov/govuk_personalisation/pull/11))
|
7
|
+
|
1
8
|
# 0.5.0
|
2
9
|
|
3
10
|
- Rename header name constants ([#7](https://github.com/alphagov/govuk_personalisation/pull/7))
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# GOV.UK Personalisation
|
2
2
|
|
3
|
-
A gem to hold shared code which other GOV.UK apps
|
3
|
+
A gem to hold shared code which other GOV.UK apps use to implement
|
4
4
|
accounts-related functionality.
|
5
5
|
|
6
6
|
## Installation
|
@@ -17,13 +17,64 @@ And then execute:
|
|
17
17
|
$ bundle install
|
18
18
|
```
|
19
19
|
|
20
|
-
##
|
20
|
+
## Usage
|
21
21
|
|
22
|
-
|
22
|
+
### Rails concern
|
23
23
|
|
24
|
-
|
24
|
+
Include the concern into a controller:
|
25
25
|
|
26
|
-
|
26
|
+
```ruby
|
27
|
+
include GovukPersonalisation::AccountConcern
|
28
|
+
```
|
29
|
+
|
30
|
+
And it will add `before_action` methods to:
|
31
|
+
|
32
|
+
- fetch the account session identifier from the request headers, making it available as `account_session_header`
|
33
|
+
- set a `Vary` response header, to ensure responses for different users are cached differently by the CDN
|
34
|
+
|
35
|
+
The following functions are available:
|
36
|
+
|
37
|
+
- `logged_in?` - check if there is an account session header
|
38
|
+
- `set_account_session_header` - replace the current session value, and set the response header the CDN uses to update the user's cookie
|
39
|
+
- `logout!` - clear the session value, and set the response header the CDN uses to remove the user's cookie
|
40
|
+
|
41
|
+
When run in development mode (`RAILS_ENV=development`), a cookie on
|
42
|
+
`dev.gov.uk` is used instead of custom headers.
|
43
|
+
|
44
|
+
### Test helpers
|
45
|
+
|
46
|
+
There are test helpers for both request and feature specs to log the
|
47
|
+
user in. Include the relevant helper:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
include GovukPersonalisation::TestHelpers::Requests
|
51
|
+
```
|
52
|
+
|
53
|
+
*or*
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
include GovukPersonalisation::TestHelpers::Features
|
57
|
+
```
|
58
|
+
|
59
|
+
And then log the user in:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
before do
|
63
|
+
mock_logged_in_session
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
If you need a specific session identifier, for example to match
|
68
|
+
against it in WebMock stubs or with the [gds-api-adapters][] test
|
69
|
+
helpers, you can pass it as an argument:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
before do
|
73
|
+
mock_logged_in_session("your-session-identifier-goes-here")
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
[gds-api-adapters]: https://github.com/alphagov/gds-api-adapters
|
27
78
|
|
28
79
|
## License
|
29
80
|
|
@@ -1,11 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "govuk_personalisation/version"
|
4
|
-
require "govuk_personalisation/
|
4
|
+
require "govuk_personalisation/controller_concern"
|
5
|
+
require "govuk_personalisation/flash"
|
5
6
|
require "govuk_personalisation/test_helpers/features"
|
6
7
|
require "govuk_personalisation/test_helpers/requests"
|
7
8
|
|
8
|
-
module GovukPersonalisation
|
9
|
-
class Error < StandardError; end
|
10
|
-
# Your code goes here...
|
11
|
-
end
|
9
|
+
module GovukPersonalisation; end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module GovukPersonalisation
|
6
|
+
module ControllerConcern
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
ACCOUNT_SESSION_INTERNAL_HEADER_NAME = "HTTP_GOVUK_ACCOUNT_SESSION"
|
10
|
+
ACCOUNT_SESSION_HEADER_NAME = "GOVUK-Account-Session"
|
11
|
+
ACCOUNT_END_SESSION_HEADER_NAME = "GOVUK-Account-End-Session"
|
12
|
+
ACCOUNT_SESSION_DEV_COOKIE_NAME = "govuk_account_session"
|
13
|
+
|
14
|
+
included do
|
15
|
+
before_action :fetch_account_session_header
|
16
|
+
before_action :set_account_vary_header
|
17
|
+
attr_accessor :account_session_header
|
18
|
+
attr_reader :account_flash
|
19
|
+
end
|
20
|
+
|
21
|
+
# Read the `GOVUK-Account-Session` request header and set the
|
22
|
+
# `@account_session_header` and `@account_flash` variables. Also
|
23
|
+
# sets a response header with an empty flash if there is a flash
|
24
|
+
# in the request.
|
25
|
+
#
|
26
|
+
# This is called as a `before_action`
|
27
|
+
#
|
28
|
+
# This should not be called after either of the
|
29
|
+
# `@govuk_account_session` or flash to return to the user have
|
30
|
+
# been changed, as those changes will be overwritten.
|
31
|
+
def fetch_account_session_header
|
32
|
+
session_with_flash =
|
33
|
+
if request.headers[ACCOUNT_SESSION_INTERNAL_HEADER_NAME]
|
34
|
+
request.headers[ACCOUNT_SESSION_INTERNAL_HEADER_NAME].presence
|
35
|
+
elsif Rails.env.development?
|
36
|
+
cookies[ACCOUNT_SESSION_DEV_COOKIE_NAME]
|
37
|
+
end
|
38
|
+
|
39
|
+
@account_session_header, flash = GovukPersonalisation::Flash.decode_session(session_with_flash)
|
40
|
+
@account_flash = (flash || []).index_with { |_| true }
|
41
|
+
@new_account_flash = {}
|
42
|
+
|
43
|
+
set_account_session_header unless @account_flash.empty?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Set the `Vary: GOVUK-Account-Session` response header.
|
47
|
+
#
|
48
|
+
# This is called as a `before_action`, to ensure that pages
|
49
|
+
# rendered using one user's session are not served to another by
|
50
|
+
# our CDN. You should only skip this action if you are certain
|
51
|
+
# that the response does not include any personalisation, or if
|
52
|
+
# you prevent caching in some other way (for example, with
|
53
|
+
# `Cache-Control: no-store`).
|
54
|
+
def set_account_vary_header
|
55
|
+
response.headers["Vary"] = [response.headers["Vary"], ACCOUNT_SESSION_HEADER_NAME].compact.join(", ")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Check if the user has a session.
|
59
|
+
#
|
60
|
+
# This does not call account-api to verify that the session is
|
61
|
+
# valid, but an invalid session would not allow a user to access
|
62
|
+
# any personal data anyway.
|
63
|
+
#
|
64
|
+
# @return [true, false] whether the user has a session
|
65
|
+
def logged_in?
|
66
|
+
account_session_header.present?
|
67
|
+
end
|
68
|
+
|
69
|
+
# Set a new session header.
|
70
|
+
#
|
71
|
+
# This should be called after any API call to account-api which
|
72
|
+
# returns a new session value. This is called automatically after
|
73
|
+
# updating the flash with `account_flash_add` or
|
74
|
+
# `account_flash_keep`
|
75
|
+
#
|
76
|
+
# Calling this after calling `logout!` will not prevent the user
|
77
|
+
# from being logged out.
|
78
|
+
#
|
79
|
+
# @param govuk_account_session [String, nil] the new session identifier
|
80
|
+
def set_account_session_header(govuk_account_session = nil)
|
81
|
+
@account_session_header = govuk_account_session if govuk_account_session
|
82
|
+
|
83
|
+
session_with_flash = GovukPersonalisation::Flash.encode_session(@account_session_header, @new_account_flash.keys)
|
84
|
+
|
85
|
+
response.headers[ACCOUNT_SESSION_HEADER_NAME] = session_with_flash
|
86
|
+
if Rails.env.development?
|
87
|
+
cookies[ACCOUNT_SESSION_DEV_COOKIE_NAME] = {
|
88
|
+
value: session_with_flash,
|
89
|
+
domain: "dev.gov.uk",
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Clear the `@account_session_header` and set the logout response
|
95
|
+
# header.
|
96
|
+
def logout!
|
97
|
+
response.headers[ACCOUNT_END_SESSION_HEADER_NAME] = "1"
|
98
|
+
@account_session_header = nil
|
99
|
+
if Rails.env.development?
|
100
|
+
cookies[ACCOUNT_SESSION_DEV_COOKIE_NAME] = {
|
101
|
+
value: "",
|
102
|
+
domain: "dev.gov.uk",
|
103
|
+
expires: 1.second.ago,
|
104
|
+
}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Add a message to the flash to return to the user. This does not
|
109
|
+
# change `account_flash`
|
110
|
+
#
|
111
|
+
# @param message [String] the message to add
|
112
|
+
#
|
113
|
+
# @return [true, false] whether the message is valid (and so has been added)
|
114
|
+
def account_flash_add(message)
|
115
|
+
return false unless GovukPersonalisation::Flash.valid_message? message
|
116
|
+
|
117
|
+
@new_account_flash[message] = true
|
118
|
+
set_account_session_header
|
119
|
+
true
|
120
|
+
end
|
121
|
+
|
122
|
+
# Copy all messages from the `account_flash` into the flash to
|
123
|
+
# return to the user.
|
124
|
+
def account_flash_keep
|
125
|
+
@new_account_flash = @account_flash.merge(@new_account_flash)
|
126
|
+
set_account_session_header
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string-literal: true
|
2
|
+
|
3
|
+
module GovukPersonalisation::Flash
|
4
|
+
SESSION_SEPARATOR = "$$"
|
5
|
+
MESSAGE_SEPARATOR = ","
|
6
|
+
MESSAGE_REGEX = /\A[a-zA-Z0-9._\-]+\z/.freeze
|
7
|
+
|
8
|
+
# Splits the session header into a session value (suitable for using
|
9
|
+
# in account-api calls) and flash messages.
|
10
|
+
#
|
11
|
+
# @param encoded_session [String] the value of the `GOVUK-Account-Session` header
|
12
|
+
#
|
13
|
+
# @return [Array(String, Array<String>), nil] the session value and the flash messages
|
14
|
+
def self.decode_session(encoded_session)
|
15
|
+
session_bits = encoded_session&.split(SESSION_SEPARATOR)
|
16
|
+
return if session_bits.blank?
|
17
|
+
|
18
|
+
if session_bits.length == 1
|
19
|
+
[session_bits[0], []]
|
20
|
+
else
|
21
|
+
[session_bits[0], session_bits[1].split(MESSAGE_SEPARATOR)]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Encodes the session value and a list of flash messages into a
|
26
|
+
# session header which can be returned to the user.
|
27
|
+
#
|
28
|
+
# @param session [String] the session value
|
29
|
+
# @param flash [Array<String>] the flash messages, which must all be `valid_message?`
|
30
|
+
#
|
31
|
+
# @return [String] the encoded session header value
|
32
|
+
def self.encode_session(session, flash)
|
33
|
+
if flash.blank?
|
34
|
+
session
|
35
|
+
else
|
36
|
+
"#{session}#{SESSION_SEPARATOR}#{flash.join(MESSAGE_SEPARATOR)}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Check if a string is valid as a flash message.
|
41
|
+
#
|
42
|
+
# @param message [String, nil] the flash message
|
43
|
+
#
|
44
|
+
# @return [true, false] whether the message is valid or not.
|
45
|
+
def self.valid_message?(message)
|
46
|
+
return false if message.nil?
|
47
|
+
|
48
|
+
message.match? MESSAGE_REGEX
|
49
|
+
end
|
50
|
+
end
|
@@ -1,8 +1,13 @@
|
|
1
1
|
module GovukPersonalisation
|
2
2
|
module TestHelpers
|
3
3
|
module Features
|
4
|
-
|
5
|
-
|
4
|
+
# Set the `GOVUK-Account-Session` request header in the page
|
5
|
+
# driver.
|
6
|
+
#
|
7
|
+
# @param session_id [String] the session identifier
|
8
|
+
# @param flash [Array<String>, nil] the flash messages
|
9
|
+
def mock_logged_in_session(session_id = "placeholder", flash = nil)
|
10
|
+
page.driver.header("GOVUK-Account-Session", GovukPersonalisation::Flash.encode_session(session_id, flash))
|
6
11
|
end
|
7
12
|
end
|
8
13
|
end
|
@@ -1,8 +1,12 @@
|
|
1
1
|
module GovukPersonalisation
|
2
2
|
module TestHelpers
|
3
3
|
module Requests
|
4
|
-
|
5
|
-
|
4
|
+
# Set the `GOVUK-Account-Session` request header.
|
5
|
+
#
|
6
|
+
# @param session_id [String] the session identifier
|
7
|
+
# @param flash [Array<String>, nil] the flash messages
|
8
|
+
def mock_logged_in_session(session_id = "placeholder", flash = nil)
|
9
|
+
request.headers["GOVUK-Account-Session"] = GovukPersonalisation::Flash.encode_session(session_id, flash)
|
6
10
|
end
|
7
11
|
end
|
8
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: govuk_personalisation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GOV.UK Dev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-06
|
11
|
+
date: 2021-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -116,7 +116,8 @@ files:
|
|
116
116
|
- bin/setup
|
117
117
|
- govuk_personalisation.gemspec
|
118
118
|
- lib/govuk_personalisation.rb
|
119
|
-
- lib/govuk_personalisation/
|
119
|
+
- lib/govuk_personalisation/controller_concern.rb
|
120
|
+
- lib/govuk_personalisation/flash.rb
|
120
121
|
- lib/govuk_personalisation/test_helpers/features.rb
|
121
122
|
- lib/govuk_personalisation/test_helpers/requests.rb
|
122
123
|
- lib/govuk_personalisation/version.rb
|
@@ -1,60 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "active_support/concern"
|
4
|
-
|
5
|
-
module GovukPersonalisation
|
6
|
-
module AccountConcern
|
7
|
-
extend ActiveSupport::Concern
|
8
|
-
|
9
|
-
ACCOUNT_SESSION_INTERNAL_HEADER_NAME = "HTTP_GOVUK_ACCOUNT_SESSION"
|
10
|
-
ACCOUNT_SESSION_HEADER_NAME = "GOVUK-Account-Session"
|
11
|
-
ACCOUNT_END_SESSION_HEADER_NAME = "GOVUK-Account-End-Session"
|
12
|
-
ACCOUNT_SESSION_DEV_COOKIE_NAME = "govuk_account_session"
|
13
|
-
|
14
|
-
included do
|
15
|
-
before_action :fetch_account_session_header
|
16
|
-
before_action :set_account_vary_header
|
17
|
-
attr_accessor :account_session_header
|
18
|
-
end
|
19
|
-
|
20
|
-
def logged_in?
|
21
|
-
account_session_header.present?
|
22
|
-
end
|
23
|
-
|
24
|
-
def fetch_account_session_header
|
25
|
-
@account_session_header =
|
26
|
-
if request.headers[ACCOUNT_SESSION_INTERNAL_HEADER_NAME]
|
27
|
-
request.headers[ACCOUNT_SESSION_INTERNAL_HEADER_NAME].presence
|
28
|
-
elsif Rails.env.development?
|
29
|
-
cookies[ACCOUNT_SESSION_DEV_COOKIE_NAME]
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def set_account_vary_header
|
34
|
-
response.headers["Vary"] = [response.headers["Vary"], ACCOUNT_SESSION_HEADER_NAME].compact.join(", ")
|
35
|
-
end
|
36
|
-
|
37
|
-
def set_account_session_header(govuk_account_session = nil)
|
38
|
-
@account_session_header = govuk_account_session if govuk_account_session
|
39
|
-
response.headers[ACCOUNT_SESSION_HEADER_NAME] = @account_session_header
|
40
|
-
if Rails.env.development?
|
41
|
-
cookies[ACCOUNT_SESSION_DEV_COOKIE_NAME] = {
|
42
|
-
value: @account_session_header,
|
43
|
-
domain: "dev.gov.uk",
|
44
|
-
}
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def logout!
|
49
|
-
response.headers[ACCOUNT_END_SESSION_HEADER_NAME] = "1"
|
50
|
-
@account_session_header = nil
|
51
|
-
if Rails.env.development?
|
52
|
-
cookies[ACCOUNT_SESSION_DEV_COOKIE_NAME] = {
|
53
|
-
value: "",
|
54
|
-
domain: "dev.gov.uk",
|
55
|
-
expires: 1.second.ago,
|
56
|
-
}
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|