Skip to content

Commit 2e31c09

Browse files
Merge pull request #307 from ivantsepp/master
Only allow files that render to HTML to be written as a Page
2 parents 48e6b7f + 7a84a0f commit 2e31c09

File tree

6 files changed

+65
-5
lines changed

6 files changed

+65
-5
lines changed

lib/jekyll-admin.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
require "jekyll-admin/urlable.rb"
3030
require "jekyll-admin/data_file.rb"
3131
require "jekyll-admin/directory.rb"
32+
require "jekyll-admin/page_without_a_file.rb"
3233

3334
# Monkey Patches
3435
require_relative "./jekyll/commands/serve"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module JekyllAdmin
2+
class PageWithoutAFile < Jekyll::Page
3+
def read_yaml(*)
4+
@data ||= {}
5+
end
6+
end
7+
end

lib/jekyll-admin/server/page.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class Server < Sinatra::Base
1212
end
1313

1414
put "/*?/?:path.:ext" do
15+
ensure_html_content
1516
write_path = relative_page_path
1617
if request_payload["path"] && request_payload["path"] != relative_page_path
1718
delete_file page_path
@@ -34,6 +35,23 @@ class Server < Sinatra::Base
3435

3536
private
3637

38+
def ensure_html_content
39+
return if html_content?
40+
content_type :json
41+
halt 422, json("error_message" => "Invalid file extension for pages")
42+
end
43+
44+
def html_content?
45+
page = JekyllAdmin::PageWithoutAFile.new(
46+
site,
47+
site.source,
48+
"",
49+
request_payload["path"] || filename
50+
)
51+
page.data = request_payload["front_matter"]
52+
page.html?
53+
end
54+
3755
def request_path
3856
sanitized_path request_payload["path"]
3957
end

spec/jekyll-admin/server/page_spec.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ def app
128128
request = {
129129
:front_matter => {},
130130
:raw_content => "test",
131+
:path => "page-new.md",
131132
}
132133
put "/pages/page-new.md", request.to_json
133134

@@ -143,6 +144,7 @@ def app
143144
request = {
144145
:front_matter => { :foo => "bar" },
145146
:raw_content => "test",
147+
:path => "page-new.md",
146148
}
147149
put "/pages/page-new.md", request.to_json
148150

@@ -157,6 +159,7 @@ def app
157159
request = {
158160
:front_matter => { :foo => "bar" },
159161
:raw_content => "test",
162+
:path => "page-dir/page-new.md",
160163
}
161164
put "/pages/page-dir/page-new.md", request.to_json
162165

@@ -167,12 +170,27 @@ def app
167170
delete_file "page-dir/page-new.md"
168171
end
169172

173+
it "does not writes a non html page" do
174+
expected_error = "Invalid file extension for pages"
175+
request = {
176+
:front_matter => { :foo => "bar" },
177+
:raw_content => "test",
178+
:path => "page-new.txt",
179+
}
180+
put "/pages/page-new.txt", request.to_json
181+
182+
expect(last_response).to be_unprocessable
183+
expect(last_response_parsed["error_message"]).to eq(expected_error)
184+
expect("page-new.md").to_not be_an_existing_file
185+
end
186+
170187
it "updates a page" do
171188
write_file "page-update.md"
172189

173190
request = {
174191
:front_matter => { :foo => "bar2" },
175192
:raw_content => "test",
193+
:path => "page-update.md",
176194
}
177195
put "/pages/page-update.md", request.to_json
178196
expect("page-update.md").to be_an_existing_file
@@ -189,6 +207,7 @@ def app
189207
request = {
190208
:front_matter => { :foo => "bar2" },
191209
:raw_content => "test",
210+
:path => "page-dir/page-update.md",
192211
}
193212
put "/pages/page-dir/page-update.md", request.to_json
194213
expect("page-dir/page-update.md").to be_an_existing_file

src/utils/api_errors.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export class BadInputError extends Error {
2+
constructor(message) {
3+
super();
4+
this.name = "BadInputError";
5+
this.message = message || 'Bad input';
6+
this.stack = (new Error()).stack;
7+
}
8+
}

src/utils/fetch.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
getUpdateErrorMessage,
77
getDeleteMessage
88
} from '../constants/lang';
9+
import { BadInputError } from './api_errors';
910

1011
/**
1112
* Fetch wrapper for GET request that dispatches actions according to the
@@ -50,18 +51,24 @@ export const put = (url, body, action_success, action_failure, dispatch) => {
5051
body
5152
})
5253
.then(res => res.json())
53-
.then(data => dispatch({
54-
type: action_success.type,
55-
[action_success.name]: data
56-
}))
54+
.then(data => {
55+
if (data.error_message){
56+
throw new BadInputError(data.error_message);
57+
}
58+
dispatch({
59+
type: action_success.type,
60+
[action_success.name]: data
61+
});
62+
})
5763
.catch(error => {
5864
dispatch({
5965
type: action_failure.type,
6066
[action_failure.name]: error
6167
});
68+
let error_message = error.name ==='BadInputError' ? error.message : getUpdateErrorMessage(action_success.name);
6269
dispatch(addNotification(
6370
getErrorMessage(),
64-
getUpdateErrorMessage(action_success.name),
71+
error_message,
6572
'error'
6673
));
6774
});

0 commit comments

Comments
 (0)