codeword 0.2.0.beta3 → 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 +4 -4
- data/CHANGELOG.md +10 -2
- data/README.md +5 -11
- data/UPGRADE-0.2.md +51 -0
- data/app/controllers/codeword/codeword_controller.rb +12 -4
- data/app/helpers/codeword/codeword_helper.rb +1 -1
- data/codeword.gemspec +3 -3
- data/lib/codeword/authentication.rb +17 -0
- data/lib/codeword/configuration.rb +30 -0
- data/lib/codeword/version.rb +1 -1
- data/lib/codeword.rb +2 -43
- metadata +11 -9
- data/script/rails +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: edc4c98d1d7d4aaeecc0e2d0b7afcb8a532753e057ae77998f804d4fc74203b7
|
4
|
+
data.tar.gz: 0abf677be13b090ab310441dd01e07b403fe7296b747f92b8729dc87cc1b21d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd5f76a4bd9cc4560fb55d2645bbe6229c00fec7a9969b003835ef85927ede1fac0eb27dcc918fe626671643e64d5e1cd2ee448379b4f5209e42deab498e70b4
|
7
|
+
data.tar.gz: 24e3c1cddb91cf2a2f08582fbde8184b81abcdf96c29fb70c10fcbcba2dcadd281a53c5e931eda35f25cb66bef32e878c121da4cd9c45f5d8f402d28f5e183c9
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
-
## [
|
1
|
+
## [0.2.0] - 2025-09-25
|
2
2
|
|
3
|
+
- BREAKING: Only support namespaced Rails credentials under `codeword` (e.g. `codeword.codeword`, `codeword.hint`, `codeword.cookie_lifetime_in_weeks`)
|
3
4
|
- BREAKING: Drop support for Rails < 7.2
|
4
5
|
- BREAKING: Rename `check_for_codeword` to `require_codeword!`
|
5
6
|
- BREAKING: Deprecate Rails secrets in favor of Rails credentials
|
6
|
-
- BREAKING:
|
7
|
+
- BREAKING: Remove lowercase ENV variable support (only uppercase ENV variables are now supported)
|
8
|
+
|
9
|
+
- Prevent open redirects by using `allow_other_host: false`
|
10
|
+
- Harden cookie with `httponly: true`, `same_site: :lax`, and `secure: request.ssl?`
|
11
|
+
- `codeword_cookie_lifetime` now returns an `ActiveSupport::Duration`; cookie expiry uses `from_now`
|
12
|
+
- Updated crawler detection regex (removed duplicate `spider` and generic `click` token)
|
13
|
+
|
14
|
+
Migration: see [UPGRADE-0.2.md](./UPGRADE-0.2.md) for steps to upgrade from 0.1.x to 0.2.0.
|
7
15
|
|
8
16
|
## [0.1.1] - 2021-12-17
|
9
17
|
|
data/README.md
CHANGED
@@ -21,22 +21,22 @@ gem 'codeword'
|
|
21
21
|
mount Codeword::Engine, at: '/codeword'
|
22
22
|
```
|
23
23
|
|
24
|
-
4. Include the `Codeword` module in your application_controller.rb file and check for codeword:
|
24
|
+
4. Include the `Codeword::Authentication` module in your application_controller.rb file and check for codeword:
|
25
25
|
|
26
26
|
```ruby
|
27
27
|
# app/controllers/application_controller.rb
|
28
28
|
class ApplicationController < ActionController::Base
|
29
|
-
include Codeword
|
29
|
+
include Codeword::Authentication
|
30
30
|
|
31
31
|
before_action :require_codeword!
|
32
32
|
end
|
33
33
|
```
|
34
34
|
|
35
|
-
5. Skip the check for codeword in the controller(s) you would like to
|
35
|
+
5. Skip the check for codeword in the controller(s) you would like to allow:
|
36
36
|
|
37
37
|
```ruby
|
38
38
|
class APIController < ApplicationController
|
39
|
-
skip_before_action :require_codeword
|
39
|
+
skip_before_action :require_codeword!
|
40
40
|
end
|
41
41
|
```
|
42
42
|
|
@@ -56,17 +56,11 @@ ENV['CODEWORD_HINT'] = 'Something that you do not tell everyone.'
|
|
56
56
|
|
57
57
|
You can add your codeword via Rails credentials in your `credentials.yml.enc` file (`$ bin/rails credentials:edit`):
|
58
58
|
|
59
|
-
```yml
|
60
|
-
codeword: "love"
|
61
|
-
codeword_hint: "Pepé Le Pew"
|
62
|
-
```
|
63
|
-
|
64
|
-
Alternately, credentials in Rails >= 5.2 may be organized under the `codeword` namespace:
|
65
|
-
|
66
59
|
```yml
|
67
60
|
codeword:
|
68
61
|
codeword: "love"
|
69
62
|
hint: "Pepé Le Pew"
|
63
|
+
cookie_lifetime_in_weeks: 4
|
70
64
|
```
|
71
65
|
|
72
66
|
**Codewords are not case-sensitive, by design. Keep it simple.**
|
data/UPGRADE-0.2.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Migrating from 0.1.x to 0.2.0
|
2
|
+
|
3
|
+
This guide walks you through the changes required to upgrade from 0.1.x to 0.2.0.
|
4
|
+
|
5
|
+
## TL;DR checklist
|
6
|
+
|
7
|
+
- Update to Rails >= 7.2.
|
8
|
+
- Move credentials to the namespaced structure under `codeword`.
|
9
|
+
- Ensure controllers use `require_codeword!` (and skip it only where access is allowed).
|
10
|
+
- Stop relying on external `return_to` redirects; they are blocked now.
|
11
|
+
|
12
|
+
## 1) Credentials: namespaced only
|
13
|
+
|
14
|
+
Codeword now reads credentials only from the namespaced structure:
|
15
|
+
|
16
|
+
```yml
|
17
|
+
# config/credentials.yml.enc
|
18
|
+
codeword:
|
19
|
+
codeword: "love"
|
20
|
+
hint: "Pepé Le Pew"
|
21
|
+
cookie_lifetime_in_weeks: 4
|
22
|
+
```
|
23
|
+
|
24
|
+
- Non‑namespaced keys like `codeword_hint:` at the root are no longer read.
|
25
|
+
- Environment variable fallbacks still work: `ENV['CODEWORD']`, `ENV['CODEWORD_HINT']`, `ENV['COOKIE_LIFETIME_IN_WEEKS']`.
|
26
|
+
|
27
|
+
## 2) Controller hook rename and usage
|
28
|
+
|
29
|
+
- Use `require_codeword!` to enforce the codeword gate.
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
class ApplicationController < ActionController::Base
|
33
|
+
include Codeword::Authentication
|
34
|
+
before_action :require_codeword!
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
- Skip it only for controllers/actions you want to allow without the codeword:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
class APIController < ApplicationController
|
42
|
+
skip_before_action :require_codeword!
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
- The old `check_for_codeword` name is deprecated; switch to `require_codeword!`.
|
47
|
+
|
48
|
+
## 3) Redirect hardening (open redirects)
|
49
|
+
|
50
|
+
- After a successful unlock, external `return_to` URLs are no longer allowed. Redirects now use `allow_other_host: false` and will fall back to the root path if unsafe.
|
51
|
+
- If you previously depended on redirecting to external domains, move that flow behind your own internal path and perform external navigation server‑side or client‑side after the unlock.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Codeword
|
2
2
|
class CodewordController < Codeword::ApplicationController
|
3
|
-
CRAWLER_REGEX = /crawl|googlebot|slurp|spider|bingbot|tracker|
|
3
|
+
CRAWLER_REGEX = /crawl|googlebot|slurp|spider|bingbot|tracker|parser/
|
4
4
|
|
5
5
|
skip_before_action :require_codeword!, raise: false
|
6
6
|
|
@@ -14,7 +14,7 @@ module Codeword
|
|
14
14
|
if params[:codeword].present?
|
15
15
|
@codeword = params[:codeword].to_s.downcase
|
16
16
|
@return_to = params[:return_to]
|
17
|
-
if @codeword == codeword_code.to_s.downcase
|
17
|
+
if @codeword == Codeword::Configuration.codeword_code.to_s.downcase
|
18
18
|
set_cookie
|
19
19
|
run_redirect
|
20
20
|
else
|
@@ -28,15 +28,23 @@ module Codeword
|
|
28
28
|
private
|
29
29
|
|
30
30
|
def set_cookie
|
31
|
-
cookies[:codeword] = {
|
31
|
+
cookies[:codeword] = {
|
32
|
+
value: @codeword.to_s.downcase,
|
33
|
+
expires: Codeword::Configuration.codeword_cookie_lifetime.from_now,
|
34
|
+
httponly: true,
|
35
|
+
secure: request.ssl?,
|
36
|
+
same_site: :lax
|
37
|
+
}
|
32
38
|
end
|
33
39
|
|
34
40
|
def run_redirect
|
35
41
|
if @return_to.present?
|
36
|
-
redirect_to @return_to.to_s
|
42
|
+
redirect_to @return_to.to_s, allow_other_host: false
|
37
43
|
else
|
38
44
|
redirect_to '/'
|
39
45
|
end
|
46
|
+
rescue ActionController::Redirecting::UnsafeRedirectError
|
47
|
+
redirect_to '/'
|
40
48
|
end
|
41
49
|
end
|
42
50
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Codeword
|
4
4
|
module CodewordHelper
|
5
5
|
def codeword_hint
|
6
|
-
@codeword_hint ||= ENV['CODEWORD_HINT'] ||
|
6
|
+
@codeword_hint ||= ENV['CODEWORD_HINT'] || Codeword::Configuration.from_credentials(:hint)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
data/codeword.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ['Dan Kim', 'gb Studio']
|
9
9
|
spec.email = ['git@dan.kim']
|
10
10
|
|
11
|
-
spec.summary = 'Lock staging servers from search engines and prying
|
11
|
+
spec.summary = 'Lock staging servers from search engines and prying eyes.'
|
12
12
|
spec.description = 'A simple gem to more elegantly place a staging server or other in-progress application behind a basic codeword. It’s easy to implement, share with clients/collaborators, and more beautiful than the typical password-protection sheet.'
|
13
13
|
spec.homepage = 'https://github.com/dankimio/codeword'
|
14
14
|
spec.license = 'MIT'
|
@@ -23,8 +23,8 @@ Gem::Specification.new do |spec|
|
|
23
23
|
|
24
24
|
spec.add_dependency 'rails', '>= 7.2'
|
25
25
|
|
26
|
-
spec.add_development_dependency 'capybara'
|
26
|
+
spec.add_development_dependency 'capybara'
|
27
27
|
spec.add_development_dependency 'debug'
|
28
28
|
spec.add_development_dependency 'launchy', '~> 2.4'
|
29
|
-
spec.add_development_dependency 'rspec-rails', '~>
|
29
|
+
spec.add_development_dependency 'rspec-rails', '~> 7.0'
|
30
30
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Codeword
|
2
|
+
module Authentication
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def require_codeword!
|
6
|
+
return unless respond_to?(:codeword) && Codeword::Configuration.codeword_code
|
7
|
+
return if cookies[:codeword].present? && cookies[:codeword] == Codeword::Configuration.codeword_code.to_s.downcase
|
8
|
+
|
9
|
+
redirect_to codeword.unlock_path(
|
10
|
+
return_to: request.fullpath.split('?codeword')[0],
|
11
|
+
codeword: params[:codeword]
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
alias_method :check_for_codeword, :require_codeword!
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Codeword
|
4
|
+
module Configuration
|
5
|
+
def self.from_credentials(setting)
|
6
|
+
store = Rails.application.credentials
|
7
|
+
|
8
|
+
store.dig(:codeword, setting)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.cookie_lifetime
|
12
|
+
@cookie_lifetime ||=
|
13
|
+
ENV['COOKIE_LIFETIME_IN_WEEKS'] ||
|
14
|
+
from_credentials(:cookie_lifetime_in_weeks)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.codeword_code
|
18
|
+
@codeword_code ||= ENV['CODEWORD'] || from_credentials(:codeword)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.codeword_cookie_lifetime
|
22
|
+
weeks = cookie_lifetime.to_f
|
23
|
+
if weeks.positive?
|
24
|
+
weeks.weeks
|
25
|
+
else
|
26
|
+
5.years
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/codeword/version.rb
CHANGED
data/lib/codeword.rb
CHANGED
@@ -1,49 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'codeword/engine'
|
4
|
+
require 'codeword/authentication'
|
5
|
+
require 'codeword/configuration'
|
4
6
|
|
5
7
|
module Codeword
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
def self.from_config(setting)
|
9
|
-
store = Rails.application.credentials
|
10
|
-
|
11
|
-
store.codeword.respond_to?(:fetch) &&
|
12
|
-
store.codeword.fetch(setting, store.public_send("codeword_#{setting}")) ||
|
13
|
-
store.public_send("codeword_#{setting}") || store.public_send(setting)
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def require_codeword!
|
19
|
-
return unless respond_to?(:codeword) && codeword_code
|
20
|
-
return if cookies[:codeword].present? && cookies[:codeword] == codeword_code.to_s.downcase
|
21
|
-
|
22
|
-
redirect_to codeword.unlock_path(
|
23
|
-
return_to: request.fullpath.split('?codeword')[0],
|
24
|
-
codeword: params[:codeword]
|
25
|
-
)
|
26
|
-
end
|
27
|
-
|
28
|
-
alias_method :check_for_codeword, :require_codeword!
|
29
|
-
|
30
|
-
def cookie_lifetime
|
31
|
-
@cookie_lifetime ||=
|
32
|
-
ENV['COOKIE_LIFETIME_IN_WEEKS'] ||
|
33
|
-
ENV['cookie_lifetime_in_weeks'] ||
|
34
|
-
Codeword.from_config(:cookie_lifetime_in_weeks)
|
35
|
-
end
|
36
|
-
|
37
|
-
def codeword_code
|
38
|
-
@codeword_code ||= ENV['CODEWORD'] || ENV['codeword'] || Codeword.from_config(:codeword)
|
39
|
-
end
|
40
|
-
|
41
|
-
def codeword_cookie_lifetime
|
42
|
-
seconds = (cookie_lifetime.to_f * 1.week).to_i
|
43
|
-
if seconds.positive?
|
44
|
-
seconds
|
45
|
-
else
|
46
|
-
5.years
|
47
|
-
end
|
48
|
-
end
|
49
8
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: codeword
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Kim
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: capybara
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
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: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: debug
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '7.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '7.0'
|
83
83
|
description: A simple gem to more elegantly place a staging server or other in-progress
|
84
84
|
application behind a basic codeword. It’s easy to implement, share with clients/collaborators,
|
85
85
|
and more beautiful than the typical password-protection sheet.
|
@@ -95,6 +95,7 @@ files:
|
|
95
95
|
- LICENSE.txt
|
96
96
|
- README.md
|
97
97
|
- Rakefile
|
98
|
+
- UPGRADE-0.2.md
|
98
99
|
- app/controllers/codeword/application_controller.rb
|
99
100
|
- app/controllers/codeword/codeword_controller.rb
|
100
101
|
- app/helpers/codeword/application_helper.rb
|
@@ -106,11 +107,12 @@ files:
|
|
106
107
|
- codeword.gemspec
|
107
108
|
- config/routes.rb
|
108
109
|
- lib/codeword.rb
|
110
|
+
- lib/codeword/authentication.rb
|
111
|
+
- lib/codeword/configuration.rb
|
109
112
|
- lib/codeword/engine.rb
|
110
113
|
- lib/codeword/version.rb
|
111
114
|
- mise.toml
|
112
115
|
- screenshot.png
|
113
|
-
- script/rails
|
114
116
|
homepage: https://github.com/dankimio/codeword
|
115
117
|
licenses:
|
116
118
|
- MIT
|
@@ -134,5 +136,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
136
|
requirements: []
|
135
137
|
rubygems_version: 3.7.1
|
136
138
|
specification_version: 4
|
137
|
-
summary: Lock staging servers from search engines and prying
|
139
|
+
summary: Lock staging servers from search engines and prying eyes.
|
138
140
|
test_files: []
|
data/script/rails
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
-
|
4
|
-
ENGINE_ROOT = File.expand_path('..', __dir__)
|
5
|
-
ENGINE_PATH = File.expand_path('../lib/codeword/engine', __dir__)
|
6
|
-
|
7
|
-
require 'rails/all'
|
8
|
-
require 'rails/engine/commands'
|