jekyll-kw-sri 0.0.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 +7 -0
- data/README.md +115 -0
- data/lib/jekyll-kw-sri.rb +81 -0
- data/lib/jekyll-kw-sri/configuration.rb +34 -0
- data/lib/jekyll-kw-sri/parser.rb +51 -0
- data/lib/version.rb +5 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2973377b85291043610eda6a787a2e0b90cd8a5bacc1e97307e12141d506922c
|
4
|
+
data.tar.gz: 0ce8ffe029793579111eb924cd2da6ae01542b597a8a8a1203275eefa2cb4302
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 562282c803da6ee51304bc436d2186b5f06e9ca66dca84453207570b9db17881be5d73ffbc5fc0bffaeaf3be77e2d56d2cd99f415a0295536e98640554850c0c
|
7
|
+
data.tar.gz: e6c3f3650a781d0391729bac08fc3ebe812c46fee4fe81b2a836d3810da207000b08a51bd3cdfec7eb5a54a45bd70d5d3494cef6c271cdda165fa9256b390ba5
|
data/README.md
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
# jekyll-kw-sri
|
2
|
+
|
3
|
+
A plugin for jekyll to calculate [Subresource Integrity][Wikipedia SRI] (SRI) hashes for CSS (even SCSS and SASS) and JS files during build time.
|
4
|
+
|
5
|
+
> **Subresource Integrity** (SRI) is a security feature that enables browsers to verify that resources they fetch (for example, from a CDN) are delivered without unexpected manipulation. It works by allowing you to provide a cryptographic hash that a fetched resource must match.
|
6
|
+
|
7
|
+
from [Mozilla docs][Mozilla Subresource Integrity]
|
8
|
+
|
9
|
+
## Configuration
|
10
|
+
|
11
|
+
Add `kw-sri` section to `_config.yml` configure the plugin globally.
|
12
|
+
|
13
|
+
```yaml
|
14
|
+
kw-sri:
|
15
|
+
createTmpfile: false
|
16
|
+
hash_type: 'sha384'
|
17
|
+
write_source_mapping_url: true
|
18
|
+
```
|
19
|
+
|
20
|
+
Configuration values
|
21
|
+
|
22
|
+
| Key | Description | Values (**default**) |
|
23
|
+
|--------------------------|---------------------------------------------------|----------------------------|
|
24
|
+
| createTmpfile | Debug-Only, save the rendered sass or scss as css | **false**, true |
|
25
|
+
| hash_type | Which kind of integrity hash | sha256, **sha384**, sha512 |
|
26
|
+
| write_source_mapping_url | Add the map-file like to the css | false, **true** |
|
27
|
+
|
28
|
+
Add `sri: true` to **Front Matter** of `<page>` or `<post>` to activate the sri plugin.
|
29
|
+
|
30
|
+
## Build gem
|
31
|
+
|
32
|
+
## Publish gem
|
33
|
+
|
34
|
+
## Run tests
|
35
|
+
|
36
|
+
```sh
|
37
|
+
bundle exec rake test
|
38
|
+
```
|
39
|
+
|
40
|
+
### Appraisal - Gemfile Generator
|
41
|
+
|
42
|
+
[GitHub](https://github.com/thoughtbot/appraisal)
|
43
|
+
|
44
|
+
1. Create a `Appraisals` file
|
45
|
+
2. Generate `Gemfiles`
|
46
|
+
|
47
|
+
```sh
|
48
|
+
bundle exec appraisal generate
|
49
|
+
```
|
50
|
+
|
51
|
+
## Notes / Hints
|
52
|
+
|
53
|
+
### Site context is empty
|
54
|
+
|
55
|
+
Inside the `render(context)` function of a `Liquid::Tag` there is a context object. With that context you can get the `site` object, anyhow when you want to cretae your temporry **site** and **context** you need a workaround.
|
56
|
+
|
57
|
+
Normal way to get the site object from the render function of a custom tag
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
site = context.registers[:site]
|
61
|
+
```
|
62
|
+
|
63
|
+
Create a temporary site and context of a **jekyll** environment
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
site = Jekyll::Site.new(Jekyll::Configuration::DEFAULTS)
|
67
|
+
context = Liquid::Context.new({}, {}, { site: site })
|
68
|
+
```
|
69
|
+
|
70
|
+
### Base class for custom tag
|
71
|
+
Use `Jekyll::Tags::IncludeRelativeTag` instead of `Liquid::Tag` as base class of the custom jekyll tag `SriScssHashTag` will help to read the content of the scss or sass files.
|
72
|
+
|
73
|
+
### Find Scss converter
|
74
|
+
|
75
|
+
Sometimes, especially during testing, the site object is not perfectly setup. So the function `find_converter_instance` will throw an error.
|
76
|
+
|
77
|
+
**Default** implementation to find the converter.
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
converter = site.find_converter_instance(Jekyll::Converters::Scss)
|
81
|
+
```
|
82
|
+
|
83
|
+
**Workaround** implementation to find the converter.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
converter = if defined? site.find_converter_instance
|
87
|
+
site.find_converter_instance(Jekyll::Converters::Scss)
|
88
|
+
else
|
89
|
+
site.getConverterImpl(::Jekyll::Converters::Scss)
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
## SRI Integrity
|
94
|
+
|
95
|
+
```shell
|
96
|
+
openssl dgst -sha256 -binary ./style.css | openssl base64 -A
|
97
|
+
```
|
98
|
+
|
99
|
+
## Setup Steps
|
100
|
+
|
101
|
+
```sh
|
102
|
+
bundle init
|
103
|
+
bundle add rake
|
104
|
+
bundle add simplecov
|
105
|
+
bundle add minitest
|
106
|
+
bundle add minitest-reporters
|
107
|
+
bundle add minitest-profile
|
108
|
+
bundle add rspec-mocks
|
109
|
+
bundle add rdiscount
|
110
|
+
bundle add redcarpet
|
111
|
+
bundle add shoulda
|
112
|
+
```
|
113
|
+
|
114
|
+
[Wikipedia SRI]: https://en.wikipedia.org/wiki/Subresource_Integrity
|
115
|
+
[Mozilla Subresource Integrity]: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'jekyll-kw-sri/configuration'
|
4
|
+
require 'jekyll-kw-sri/parser'
|
5
|
+
|
6
|
+
require 'jekyll'
|
7
|
+
|
8
|
+
module Jekyll
|
9
|
+
module KargWare
|
10
|
+
# jekyll-kw-sri custom tag
|
11
|
+
class SriScssHashTag < Jekyll::Tags::IncludeRelativeTag
|
12
|
+
# class SriScssHashTag < Liquid::Tag
|
13
|
+
def initialize(tag_name, input, tokens)
|
14
|
+
super
|
15
|
+
|
16
|
+
raise 'Please enter a file path' if input.length <= 0
|
17
|
+
|
18
|
+
@scss_file = strip_or_self(input)
|
19
|
+
# File.exists? is file?
|
20
|
+
|
21
|
+
@tag_name = tag_name
|
22
|
+
end
|
23
|
+
|
24
|
+
# def syntax_example
|
25
|
+
# "{% #{@tag_name} css/main.scss %}"
|
26
|
+
# end
|
27
|
+
|
28
|
+
def render(context)
|
29
|
+
# return '' unless context.registers[:page]['sri']
|
30
|
+
|
31
|
+
# # Read the global configuration
|
32
|
+
# @sri_config = context.registers[:site].config['kw-sri'] || {}
|
33
|
+
|
34
|
+
cache_compiled_scss(@file, context, lambda {
|
35
|
+
if context.nil? || context.registers[:site].nil?
|
36
|
+
puts 'WARNING: There was no context, generate default site and context'
|
37
|
+
site = Jekyll::Site.new(Jekyll::Configuration::DEFAULTS)
|
38
|
+
context = Liquid::Context.new({}, {}, { site: site })
|
39
|
+
else
|
40
|
+
site = context.registers[:site]
|
41
|
+
end
|
42
|
+
|
43
|
+
converter = site.find_converter_instance(Jekyll::Converters::Scss)
|
44
|
+
|
45
|
+
result = super(context)
|
46
|
+
scss = result.gsub(/^---.*---/m, '')
|
47
|
+
data = converter.convert(scss)
|
48
|
+
|
49
|
+
Integrity::Parser.new(@sri_config).calc_integrity(@scss_file, data)
|
50
|
+
})
|
51
|
+
end
|
52
|
+
|
53
|
+
def cache_compiled_scss(path, _context, compute)
|
54
|
+
# @@cached_scss ||= {}
|
55
|
+
# if @@cached_scss.key?(path)
|
56
|
+
# @@cached_scss[path]
|
57
|
+
# else
|
58
|
+
# @@cached_scss[path] = compute.call
|
59
|
+
# end
|
60
|
+
|
61
|
+
@cached_scss ||= {}
|
62
|
+
if @cached_scss.key?(path)
|
63
|
+
@cached_scss[path]
|
64
|
+
else
|
65
|
+
@cached_scss[path] = compute.call
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# https://stackoverflow.com/a/1000975
|
70
|
+
def strip_or_self(str)
|
71
|
+
str.strip! || str
|
72
|
+
end
|
73
|
+
|
74
|
+
def tag_includes_dirs(context)
|
75
|
+
[context.registers[:site].source].freeze
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
Liquid::Template.register_tag('sri_scss_hash', Jekyll::KargWare::SriScssHashTag)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module KargWare
|
5
|
+
module Integrity
|
6
|
+
# jekyll-kw-sri configuration class
|
7
|
+
class Configuration
|
8
|
+
attr_accessor :hash_type, :write_source_mapping_url, :create_tmpfile
|
9
|
+
|
10
|
+
DEFAULT_CONFIG = {
|
11
|
+
'hashType' => 'sha384',
|
12
|
+
'writeSourceMappingURL' => true,
|
13
|
+
'createTmpfile' => false
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
def initialize(options)
|
17
|
+
options = generate_option_hash(options)
|
18
|
+
|
19
|
+
@hash_type = options['hashType']
|
20
|
+
@write_source_mapping_url = options['writeSourceMappingURL']
|
21
|
+
@create_tmpfile = options['createTmpfile']
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def generate_option_hash(options)
|
27
|
+
DEFAULT_CONFIG.merge(options)
|
28
|
+
rescue TypeError
|
29
|
+
DEFAULT_CONFIG
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'digest'
|
4
|
+
|
5
|
+
module Jekyll
|
6
|
+
module KargWare
|
7
|
+
module Integrity
|
8
|
+
# jekyll-kw-sri parser class
|
9
|
+
class Parser
|
10
|
+
attr_reader :configuration
|
11
|
+
|
12
|
+
def initialize(options = {})
|
13
|
+
@configuration = Configuration.new(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def calc_integrity(filename, data)
|
17
|
+
hash_type = @configuration.hash_type
|
18
|
+
|
19
|
+
data_modified = add_source_mapping_url(filename, data)
|
20
|
+
|
21
|
+
# Debuging, save rendered css file as tmp file
|
22
|
+
File.open(".#{filename}.tmp", 'w') { |file| file.write(data_modified) } if @configuration.create_tmpfile
|
23
|
+
|
24
|
+
case hash_type
|
25
|
+
when 'sha256'
|
26
|
+
"sha256-#{Digest::SHA256.base64digest data_modified}"
|
27
|
+
when 'sha384'
|
28
|
+
"sha384-#{Digest::SHA384.base64digest data_modified}"
|
29
|
+
when 'sha512'
|
30
|
+
"sha512-#{Digest::SHA512.base64digest data_modified}"
|
31
|
+
else
|
32
|
+
raise Jekyll::KargWare::Integrity::InvalidHashTypeException, "The type of the hash '#{hash_type}' is invalid!'"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_source_mapping_url(filename, data)
|
37
|
+
if @configuration.write_source_mapping_url
|
38
|
+
base = File.basename(filename)
|
39
|
+
base = base.sub! 'scss', 'css'
|
40
|
+
|
41
|
+
data + "\n/*# sourceMappingURL=#{base}.map */"
|
42
|
+
else
|
43
|
+
data
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class InvalidHashTypeException < Gem::Exception; end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jekyll-kw-sri
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicolas Karg
|
8
|
+
- n13.org - Open-Source by KargWare
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2020-11-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: jekyll
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '4.0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '4.0'
|
28
|
+
description: Jekyll plugin which calculate the integrity hash of CSS (SCSS, SASS)
|
29
|
+
and JS.
|
30
|
+
email: rubygems.org@n13.org
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- README.md
|
36
|
+
- lib/jekyll-kw-sri.rb
|
37
|
+
- lib/jekyll-kw-sri/configuration.rb
|
38
|
+
- lib/jekyll-kw-sri/parser.rb
|
39
|
+
- lib/version.rb
|
40
|
+
homepage: https://github.com/n13org/jekyll-kw-sri
|
41
|
+
licenses:
|
42
|
+
- MIT
|
43
|
+
metadata: {}
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '2.7'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubygems_version: 3.1.2
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: Jekyll CSS/JS integrity hash plugin
|
63
|
+
test_files: []
|