tdiary 5.5.0 → 5.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 +2 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +37 -37
- data/doc/UPGRADE.md +1 -1
- data/lib/tdiary/admin.rb +11 -13
- data/lib/tdiary/application.rb +2 -7
- data/lib/tdiary/author_only_base.rb +78 -9
- data/lib/tdiary/base.rb +2 -2
- data/lib/tdiary/cgi_adapter.rb +7 -5
- data/lib/tdiary/cgi_compat.rb +27 -95
- data/lib/tdiary/configuration.rb +4 -0
- data/lib/tdiary/core_ext.rb +146 -1
- data/lib/tdiary/dispatcher/index_main.rb +5 -23
- data/lib/tdiary/dispatcher/update_main.rb +2 -17
- data/lib/tdiary/dispatcher.rb +29 -15
- data/lib/tdiary/filter/default.rb +2 -2
- data/lib/tdiary/filter/spam.rb +2 -2
- data/lib/tdiary/filter.rb +1 -1
- data/lib/tdiary/plugin/00default.rb +18 -3
- data/lib/tdiary/plugin/en/00default.rb +15 -0
- data/lib/tdiary/plugin/ja/00default.rb +15 -0
- data/lib/tdiary/plugin.rb +1 -1
- data/lib/tdiary/rack/error_handler.rb +36 -0
- data/lib/tdiary/rack.rb +1 -0
- data/lib/tdiary/request.rb +12 -2
- data/lib/tdiary/server.rb +25 -3
- data/lib/tdiary/version.rb +1 -1
- data/lib/tdiary/view.rb +33 -28
- data/lib/tdiary/view_helper.rb +10 -2
- data/lib/tdiary.rb +6 -1
- data/misc/plugin/image.rb +1 -1
- data/misc/plugin/makerss.rb +3 -3
- data/tdiary.conf.sample +8 -0
- data/tdiary.conf.sample-en +8 -0
- data/vendor/bundle/ruby/3.4.0/cache/net-imap-0.6.6.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/cache/net-protocol-0.3.0.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/cache/rack-3.2.7.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/cgi-0.5.2/gem_make.out +5 -5
- data/vendor/bundle/ruby/3.4.0/extensions/x86_64-linux/3.4.0/date-3.5.1/gem_make.out +5 -5
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/Gemfile +3 -4
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/README.md +1 -1
- data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.6.6/Rakefile +24 -0
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/command_data.rb +62 -92
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/config/attr_accessors.rb +8 -9
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/config/attr_inheritance.rb +64 -1
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/config/attr_version_defaults.rb +1 -4
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/config.rb +209 -35
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/connection_state.rb +1 -1
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/data_encoding.rb +127 -27
- data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.6.6/lib/net/imap/errors.rb +372 -0
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/esearch_result.rb +6 -0
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/response_data.rb +90 -11
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/response_parser/parser_utils.rb +14 -23
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/response_parser.rb +41 -26
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/response_reader.rb +16 -21
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/scram_authenticator.rb +3 -3
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/search_result.rb +11 -1
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sequence_set.rb +620 -312
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/uidplus_data.rb +2 -63
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap.rb +279 -162
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/net-imap.gemspec +1 -1
- data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/rdoc.rake +1 -18
- data/vendor/bundle/ruby/3.4.0/gems/{net-protocol-0.2.2/LICENSE.txt → net-protocol-0.3.0/BSDL} +3 -3
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.3.0/COPYING +56 -0
- data/vendor/bundle/ruby/3.4.0/gems/{net-protocol-0.2.2 → net-protocol-0.3.0}/lib/net/protocol.rb +58 -4
- data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/CHANGELOG.md +54 -1
- data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/utils.rb +3 -3
- data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/version.rb +1 -1
- data/vendor/bundle/ruby/3.4.0/specifications/{net-imap-0.5.15.gemspec → net-imap-0.6.6.gemspec} +4 -4
- data/vendor/bundle/ruby/3.4.0/specifications/{net-protocol-0.2.2.gemspec → net-protocol-0.3.0.gemspec} +5 -5
- data/vendor/bundle/ruby/3.4.0/specifications/{rack-3.2.6.gemspec → rack-3.2.7.gemspec} +3 -3
- data/views/tdiary.rconf +2 -0
- metadata +127 -131
- data/vendor/bundle/ruby/3.4.0/cache/net-imap-0.5.15.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/cache/net-protocol-0.2.2.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/cache/rack-3.2.6.gem +0 -0
- data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.5.15/Rakefile +0 -13
- data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.5.15/lib/net/imap/data_lite.rb +0 -226
- data/vendor/bundle/ruby/3.4.0/gems/net-imap-0.5.15/lib/net/imap/errors.rb +0 -118
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/Gemfile +0 -7
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/Rakefile +0 -10
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/bin/console +0 -14
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/bin/setup +0 -8
- data/vendor/bundle/ruby/3.4.0/gems/net-protocol-0.2.2/net-protocol.gemspec +0 -33
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/BSDL +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/COPYING +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/LICENSE.txt +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/docs/styles.css +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/authenticators.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/config/attr_type_coercion.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/deprecated_client_options.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/fetch_data.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/flags.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/anonymous_authenticator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/authentication_exchange.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/authenticators.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/client_adapter.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/cram_md5_authenticator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/digest_md5_authenticator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/external_authenticator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/gs2_header.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/login_authenticator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/oauthbearer_authenticator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/plain_authenticator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/protocol_adapters.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/scram_algorithm.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/stringprep.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl/xoauth2_authenticator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/sasl_adapter.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep/nameprep.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep/saslprep.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep/saslprep_tables.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep/tables.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep/trace.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/stringprep.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/lib/net/imap/vanished_data.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/benchmarks.rake +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/rfcs.rake +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/saslprep.rake +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/rakelib/string_prep_tables_generator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-imap-0.5.15 → net-imap-0.6.6}/sample/net-imap.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{net-protocol-0.2.2 → net-protocol-0.3.0}/README.md +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/CONTRIBUTING.md +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/MIT-LICENSE +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/README.md +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/SPEC.rdoc +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/auth/abstract/handler.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/auth/abstract/request.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/auth/basic.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/bad_request.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/body_proxy.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/builder.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/cascade.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/common_logger.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/conditional_get.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/config.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/constants.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/content_length.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/content_type.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/deflater.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/directory.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/etag.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/events.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/files.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/head.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/headers.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/lint.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/lock.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/media_type.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/method_override.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mime.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mock.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mock_request.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/mock_response.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart/generator.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart/parser.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart/uploaded_file.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/multipart.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/null_logger.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/query_parser.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/recursive.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/reloader.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/request.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/response.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/rewindable_input.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/runtime.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/sendfile.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/show_exceptions.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/show_status.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/static.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/tempfile_reaper.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack/urlmap.rb +0 -0
- /data/vendor/bundle/ruby/3.4.0/gems/{rack-3.2.6 → rack-3.2.7}/lib/rack.rb +0 -0
data/lib/tdiary/core_ext.rb
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
require 'emot'
|
|
2
2
|
|
|
3
3
|
module TDiary
|
|
4
|
+
# CGI-semantics readers shared by TDiary::Request and the CGICompat
|
|
5
|
+
# facade (which forwards env to the request it wraps, so state memoized
|
|
6
|
+
# in the env is visible through either object).
|
|
4
7
|
module RequestExtension
|
|
5
8
|
# backward compatibility, returns NOT mobile phone always
|
|
6
9
|
def mobile_agent?
|
|
@@ -11,6 +14,147 @@ module TDiary
|
|
|
11
14
|
def smartphone?
|
|
12
15
|
false
|
|
13
16
|
end
|
|
17
|
+
|
|
18
|
+
# true when the endpoint runs behind a web server (CGI/FCGI hosting,
|
|
19
|
+
# which sets tdiary.static_assets in the env) that serves the js/ and
|
|
20
|
+
# theme/ directories itself; false on the Rack path, where
|
|
21
|
+
# TDiary::Application serves them under assets/
|
|
22
|
+
def static_assets?
|
|
23
|
+
env['tdiary.static_assets'] ? true : false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# params with CGI semantics, unlike Rack::Request#params: POST reads
|
|
27
|
+
# only the body, every value is an Array, unknown keys yield [],
|
|
28
|
+
# duplicated keys collect all values, broken UTF-8 input is retried
|
|
29
|
+
# as Shift_JIS and multipart uploads are normalized to their
|
|
30
|
+
# tempfiles. Memoized so the request and its CGICompat facade (which
|
|
31
|
+
# delegates here) share one Hash; plugins mutate it through
|
|
32
|
+
# @cgi.params.
|
|
33
|
+
def cgi_params
|
|
34
|
+
@cgi_params ||= build_cgi_params
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# single-value accessor over cgi_params; nil when the key is absent
|
|
38
|
+
def param( key, idx = 0 )
|
|
39
|
+
cgi_params[key][idx]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def valid?( param, idx = 0 )
|
|
43
|
+
cgi_params[param] and cgi_params[param][idx] and cgi_params[param][idx].length > 0
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# multi-value cookies, unlike Rack::Request#cookies: CGI::Cookie
|
|
47
|
+
# splits each value on '&' (the tdiary cookie carries 'name&mail')
|
|
48
|
+
def cgi_cookies
|
|
49
|
+
@cgi_cookies ||= CGI::Cookie.parse( env['HTTP_COOKIE'] )
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# TDiaryView hides the referer for the rest of the request when the
|
|
53
|
+
# referer filters reject it; plugins observe nil through the @cgi
|
|
54
|
+
# facade too, which delegates both methods to the request
|
|
55
|
+
def hide_referer!
|
|
56
|
+
@referer_hidden = true
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def referer
|
|
60
|
+
@referer_hidden ? nil : env['HTTP_REFERER']
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def remote_addr
|
|
64
|
+
env['REMOTE_ADDR']
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def remote_user
|
|
68
|
+
env['REMOTE_USER']
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def https?
|
|
72
|
+
return true if env['HTTP_X_FORWARDED_PROTO'] == 'https'
|
|
73
|
+
return false if env['HTTPS'].nil? or /off/i =~ env['HTTPS'] or env['HTTPS'] == ''
|
|
74
|
+
true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# not Rack::Request#base_url (scheme and host only): the CGI flavour
|
|
78
|
+
# with the SCRIPT_NAME dirname and a trailing '/'
|
|
79
|
+
def tdiary_base_url
|
|
80
|
+
script_name = env['SCRIPT_NAME']
|
|
81
|
+
return '' unless script_name
|
|
82
|
+
begin
|
|
83
|
+
script_dirname = script_name.empty? ? '' : File::dirname( script_name )
|
|
84
|
+
server_name = env['SERVER_NAME']
|
|
85
|
+
server_port = env['SERVER_PORT'].to_i
|
|
86
|
+
if https?
|
|
87
|
+
port = (server_port == 443) ? '' : ':' + server_port.to_s
|
|
88
|
+
"https://#{server_name}#{port}#{script_dirname}/"
|
|
89
|
+
else
|
|
90
|
+
port = (server_port == 80) ? '' : ':' + server_port.to_s
|
|
91
|
+
"http://#{server_name}#{port}#{script_dirname}/"
|
|
92
|
+
end.sub(%r|/+$|, '/')
|
|
93
|
+
rescue SecurityError
|
|
94
|
+
''
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def build_cgi_params
|
|
101
|
+
source =
|
|
102
|
+
if env['REQUEST_METHOD'] == 'POST'
|
|
103
|
+
if %r|\Amultipart/form-data|.match?( env['CONTENT_TYPE'].to_s )
|
|
104
|
+
self.POST
|
|
105
|
+
else
|
|
106
|
+
# Rack's nested query parser behind Rack::Request#POST keeps
|
|
107
|
+
# only the last of duplicated keys; CGI collects all of them.
|
|
108
|
+
# CGI also splits on ';' as well as '&', and tDiary's own edit
|
|
109
|
+
# links (00default.rb, edit_today.rb) still use ';'
|
|
110
|
+
::Rack::Utils.parse_query( read_raw_body, '&;' )
|
|
111
|
+
end
|
|
112
|
+
else
|
|
113
|
+
::Rack::Utils.parse_query( env['QUERY_STRING'].to_s, '&;' )
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
params = {}
|
|
117
|
+
source.each do |key, value|
|
|
118
|
+
values = value.kind_of?( Array ) ? value : [value]
|
|
119
|
+
params[key] = values.map {|v| normalize_cgi_value( v ) }
|
|
120
|
+
end
|
|
121
|
+
params.default = []
|
|
122
|
+
params
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def read_raw_body
|
|
126
|
+
input = env['rack.input']
|
|
127
|
+
return '' unless input
|
|
128
|
+
# Rack::Request#POST leaves rack.input at EOF, so rewind first in
|
|
129
|
+
# case the request params were already parsed
|
|
130
|
+
input.rewind if input.respond_to?( :rewind )
|
|
131
|
+
body = input.read
|
|
132
|
+
input.rewind if input.respond_to?( :rewind )
|
|
133
|
+
body || ''
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def normalize_cgi_value( value )
|
|
137
|
+
if value.kind_of?( Hash ) and value[:tempfile]
|
|
138
|
+
# Rack multipart file upload: expose an object responding to
|
|
139
|
+
# read, which is all the consumers use
|
|
140
|
+
value[:tempfile]
|
|
141
|
+
else
|
|
142
|
+
repair_encoding( value.to_s )
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# CGI/FCGI hosting retries broken UTF-8 input as Shift_JIS. The same
|
|
147
|
+
# fallback is applied to each value: invalid UTF-8 is converted from
|
|
148
|
+
# Shift_JIS when possible, otherwise scrubbed.
|
|
149
|
+
def repair_encoding( str )
|
|
150
|
+
str = str.dup.force_encoding( Encoding::UTF_8 ) unless str.encoding == Encoding::UTF_8
|
|
151
|
+
return str if str.valid_encoding?
|
|
152
|
+
begin
|
|
153
|
+
str.dup.force_encoding( Encoding::Shift_JIS ).encode( Encoding::UTF_8 )
|
|
154
|
+
rescue EncodingError
|
|
155
|
+
str.scrub
|
|
156
|
+
end
|
|
157
|
+
end
|
|
14
158
|
end
|
|
15
159
|
end
|
|
16
160
|
|
|
@@ -54,7 +198,8 @@ end
|
|
|
54
198
|
require 'tdiary/cgi_compat'
|
|
55
199
|
|
|
56
200
|
# the @cgi facade for Rack-hosted requests. Kept as a toplevel constant
|
|
57
|
-
#
|
|
201
|
+
# only for third-party plugins that switch behaviour with
|
|
202
|
+
# @cgi.is_a?(RackCGI); in-repo code reads static_assets? instead.
|
|
58
203
|
class RackCGI < TDiary::CGICompat; end
|
|
59
204
|
|
|
60
205
|
# Local Variables:
|
|
@@ -16,20 +16,18 @@ module TDiary
|
|
|
16
16
|
|
|
17
17
|
def run
|
|
18
18
|
begin
|
|
19
|
-
status = nil
|
|
20
19
|
@tdiary = create_tdiary
|
|
21
20
|
|
|
22
21
|
begin
|
|
22
|
+
status = 200
|
|
23
23
|
head = {
|
|
24
24
|
'content-type' => 'text/html; charset=UTF-8',
|
|
25
25
|
'vary' => 'User-Agent'
|
|
26
26
|
}
|
|
27
|
-
head['status'] = status if status
|
|
28
27
|
body = ''
|
|
29
|
-
head['
|
|
28
|
+
head['last-modified'] = tdiary.last_modified.httpdate
|
|
30
29
|
|
|
31
30
|
if request.head?
|
|
32
|
-
head['pragma'] = 'no-cache'
|
|
33
31
|
head['cache-control'] = 'no-cache'
|
|
34
32
|
return TDiary::Response.new( '', 200, head )
|
|
35
33
|
else
|
|
@@ -37,15 +35,12 @@ module TDiary
|
|
|
37
35
|
body = tdiary.eval_rhtml
|
|
38
36
|
head['etag'] = %Q["#{OpenSSL::Digest::SHA256.hexdigest( body )}"]
|
|
39
37
|
if request.env['HTTP_IF_NONE_MATCH'] == head['etag'] and request.get? then
|
|
40
|
-
|
|
38
|
+
status = 304
|
|
41
39
|
else
|
|
42
|
-
head['charset'] = conf.encoding
|
|
43
40
|
head['content-length'] = body.bytesize.to_s
|
|
44
41
|
end
|
|
45
|
-
head['pragma'] = 'no-cache'
|
|
46
42
|
head['cache-control'] = 'no-cache'
|
|
47
|
-
|
|
48
|
-
res = TDiary::Response.new( body, ::TDiary::Dispatcher.extract_status_for_legacy_tdiary( head ), head )
|
|
43
|
+
res = TDiary::Response.new( body, status, head )
|
|
49
44
|
res.set_header('Set-Cookie', tdiary.cookies.map(&:to_s)) if tdiary && tdiary.cookies.size > 0
|
|
50
45
|
res
|
|
51
46
|
end
|
|
@@ -56,20 +51,7 @@ module TDiary
|
|
|
56
51
|
TDiary::Response.new( body, 404, { 'content-type' => 'text/html' } )
|
|
57
52
|
end
|
|
58
53
|
rescue TDiary::ForceRedirect
|
|
59
|
-
|
|
60
|
-
#'Location' => $!.path
|
|
61
|
-
'content-type' => 'text/html',
|
|
62
|
-
}
|
|
63
|
-
body = %Q[
|
|
64
|
-
<html>
|
|
65
|
-
<head>
|
|
66
|
-
<meta http-equiv="refresh" content="1;url=#{$!.path}">
|
|
67
|
-
<title>moving...</title>
|
|
68
|
-
</head>
|
|
69
|
-
<body>Wait or <a href="#{$!.path}">Click here!</a></body>
|
|
70
|
-
</html>]
|
|
71
|
-
# TODO return code should be 302? (current behaviour returns 200)
|
|
72
|
-
res = TDiary::Response.new( body, 200, head )
|
|
54
|
+
res = TDiary::Response.new( '', 303, { 'location' => $!.path } )
|
|
73
55
|
res.set_header('Set-Cookie', tdiary.cookies.map(&:to_s)) if tdiary && tdiary.cookies.size > 0
|
|
74
56
|
res
|
|
75
57
|
end
|
|
@@ -21,28 +21,13 @@ module TDiary
|
|
|
21
21
|
body = tdiary.eval_rhtml
|
|
22
22
|
head = {
|
|
23
23
|
'content-type' => 'text/html; charset=UTF-8',
|
|
24
|
-
'charset' => conf.encoding,
|
|
25
24
|
'content-length' => body.bytesize.to_s,
|
|
26
|
-
'vary' => 'User-Agent'
|
|
27
|
-
'x-frame-options' => 'SAMEORIGIN'
|
|
25
|
+
'vary' => 'User-Agent'
|
|
28
26
|
}
|
|
29
27
|
body = ( request.head? ? '' : body )
|
|
30
28
|
TDiary::Response.new( body, 200, head )
|
|
31
29
|
rescue TDiary::ForceRedirect
|
|
32
|
-
|
|
33
|
-
#'Location' => $!.path
|
|
34
|
-
'content-type' => 'text/html',
|
|
35
|
-
}
|
|
36
|
-
body = %Q[
|
|
37
|
-
<html>
|
|
38
|
-
<head>
|
|
39
|
-
<meta http-equiv="refresh" content="1;url=#{$!.path}">
|
|
40
|
-
<title>moving...</title>
|
|
41
|
-
</head>
|
|
42
|
-
<body>Wait or <a href="#{$!.path}">Click here!</a></body>
|
|
43
|
-
</html>]
|
|
44
|
-
# TODO return code should be 302? (current behaviour returns 200)
|
|
45
|
-
res = TDiary::Response.new( body, 200, head )
|
|
30
|
+
res = TDiary::Response.new( '', 303, { 'location' => $!.path } )
|
|
46
31
|
res.set_header('Set-Cookie', tdiary.cookies.map(&:to_s)) if tdiary && tdiary.cookies.size > 0
|
|
47
32
|
res
|
|
48
33
|
end
|
data/lib/tdiary/dispatcher.rb
CHANGED
|
@@ -17,24 +17,13 @@ module TDiary
|
|
|
17
17
|
|
|
18
18
|
def call( env )
|
|
19
19
|
request = adopt_rack_request_to_plain_old_tdiary_style( env )
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
main = @target.new( request )
|
|
21
|
+
response = main.run
|
|
22
|
+
apply_security_headers( response, request, main.conf )
|
|
23
|
+
response.to_a
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
class << self
|
|
26
|
-
# FIXME temporary method during (scratch) refactoring
|
|
27
|
-
def extract_status_for_legacy_tdiary( head )
|
|
28
|
-
status_str = head.delete('status')
|
|
29
|
-
return 200 if !status_str || status_str.empty?
|
|
30
|
-
|
|
31
|
-
if m = status_str.match(/(\d+)\s(.+)\Z/)
|
|
32
|
-
m[1].to_i
|
|
33
|
-
else
|
|
34
|
-
200
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
27
|
def index
|
|
39
28
|
new( :index )
|
|
40
29
|
end
|
|
@@ -48,6 +37,31 @@ module TDiary
|
|
|
48
37
|
|
|
49
38
|
private
|
|
50
39
|
|
|
40
|
+
def apply_security_headers( response, request, conf )
|
|
41
|
+
response.set_header( 'x-content-type-options', 'nosniff' )
|
|
42
|
+
apply_frame_restrictions( response, conf )
|
|
43
|
+
response.set_header( 'referrer-policy', conf.referrer_policy ) if conf.referrer_policy
|
|
44
|
+
response.set_header( 'strict-transport-security', conf.hsts ) if conf.hsts && request.ssl?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# The update target is an authenticated admin UI and always forbids
|
|
48
|
+
# cross-origin framing; the index target follows conf.x_frame_options.
|
|
49
|
+
# CSP frame-ancestors is the standard control, X-Frame-Options is kept
|
|
50
|
+
# alongside for legacy user agents.
|
|
51
|
+
def apply_frame_restrictions( response, conf )
|
|
52
|
+
if @target == UpdateMain
|
|
53
|
+
response.set_header( 'content-security-policy', "frame-ancestors 'self'" )
|
|
54
|
+
response.set_header( 'x-frame-options', 'SAMEORIGIN' )
|
|
55
|
+
elsif conf.x_frame_options
|
|
56
|
+
ancestors = case conf.x_frame_options.upcase
|
|
57
|
+
when 'SAMEORIGIN' then "'self'"
|
|
58
|
+
when 'DENY' then "'none'"
|
|
59
|
+
end
|
|
60
|
+
response.set_header( 'content-security-policy', "frame-ancestors #{ancestors}" ) if ancestors
|
|
61
|
+
response.set_header( 'x-frame-options', conf.x_frame_options )
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
51
65
|
def adopt_rack_request_to_plain_old_tdiary_style( env )
|
|
52
66
|
# rebuffer rack.input into a rewindable StringIO; both
|
|
53
67
|
# Rack::Request and CGICompat read the body from it
|
|
@@ -9,7 +9,7 @@ module TDiary
|
|
|
9
9
|
module Filter
|
|
10
10
|
class DefaultFilter < Filter
|
|
11
11
|
def comment_filter( diary, comment )
|
|
12
|
-
if 'POST' != @
|
|
12
|
+
if 'POST' != @request.request_method then
|
|
13
13
|
return false
|
|
14
14
|
end
|
|
15
15
|
if comment.name.strip.empty? or comment.body.strip.empty? then
|
|
@@ -29,7 +29,7 @@ module TDiary
|
|
|
29
29
|
false
|
|
30
30
|
#elsif /[\x00-\x20\x7f-\xff]/ =~ referer then
|
|
31
31
|
# false
|
|
32
|
-
elsif @conf.bot =~ @
|
|
32
|
+
elsif @conf.bot =~ @request.user_agent
|
|
33
33
|
false
|
|
34
34
|
elsif %r|^https?://|i =~ referer
|
|
35
35
|
ref = CGI::unescape( referer.sub( /#.*$/, '' ).sub( /\?\d{8}$/, '' ) ).force_encoding('ASCII-8BIT')
|
data/lib/tdiary/filter/spam.rb
CHANGED
|
@@ -228,8 +228,8 @@ module TDiary
|
|
|
228
228
|
return @filter_mode
|
|
229
229
|
end
|
|
230
230
|
|
|
231
|
-
if @bad_ips.detect {|p| p =~ @
|
|
232
|
-
debug( "ip address blacklisted: /#{p}/ =~ #{@
|
|
231
|
+
if @bad_ips.detect {|p| p =~ @request.remote_addr}
|
|
232
|
+
debug( "ip address blacklisted: /#{p}/ =~ #{@request.remote_addr}" )
|
|
233
233
|
comment.show = false
|
|
234
234
|
return @filter_mode
|
|
235
235
|
end
|
data/lib/tdiary/filter.rb
CHANGED
|
@@ -35,7 +35,7 @@ module TDiary
|
|
|
35
35
|
return if @debug_mode == DEBUG_NONE
|
|
36
36
|
return if @debug_mode == DEBUG_SPAM and level == DEBUG_FULL
|
|
37
37
|
|
|
38
|
-
TDiary.logger.info("#{@
|
|
38
|
+
TDiary.logger.info("#{@request.remote_addr}->#{(@request.param('date') || 'no date').dump}: #{msg}")
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
end
|
|
@@ -372,8 +372,18 @@ def script_tag_query_string
|
|
|
372
372
|
"?#{TDIARY_VERSION}#{Time::now.strftime('%Y%m%d')}"
|
|
373
373
|
end
|
|
374
374
|
|
|
375
|
+
# base URL the static assets are served from, when specified in
|
|
376
|
+
# tdiary.conf: @options['assets_url'] = 'https://assets.example.org/tdiary'
|
|
377
|
+
# It expects the merged layout the Rack assets/ mount serves (js files and
|
|
378
|
+
# theme directories under one root) and wins over the hosting default on
|
|
379
|
+
# every path (Rack, CGI and FCGI).
|
|
380
|
+
def configured_assets_url
|
|
381
|
+
url = @conf['assets_url']
|
|
382
|
+
url && !url.empty? ? url.chomp('/') : nil
|
|
383
|
+
end
|
|
384
|
+
|
|
375
385
|
def js_url
|
|
376
|
-
@cgi.
|
|
386
|
+
configured_assets_url || (@cgi.static_assets? ? 'js' : 'assets')
|
|
377
387
|
end
|
|
378
388
|
|
|
379
389
|
def script_tag
|
|
@@ -396,7 +406,7 @@ def script_tag
|
|
|
396
406
|
end
|
|
397
407
|
|
|
398
408
|
def theme_url
|
|
399
|
-
@cgi.
|
|
409
|
+
configured_assets_url || (@cgi.static_assets? ? 'theme' : 'assets')
|
|
400
410
|
end
|
|
401
411
|
|
|
402
412
|
def css_tag
|
|
@@ -748,6 +758,10 @@ def saveconf_default
|
|
|
748
758
|
@conf['base_url'] = @cgi.params['base_url'][0]
|
|
749
759
|
@conf.x_frame_options = @cgi.params['x_frame_options'][0]
|
|
750
760
|
@conf.x_frame_options = nil if @conf.x_frame_options.empty?
|
|
761
|
+
@conf.referrer_policy = @cgi.params['referrer_policy'][0]
|
|
762
|
+
@conf.referrer_policy = nil if @conf.referrer_policy.empty?
|
|
763
|
+
@conf.hsts = @cgi.params['hsts'][0]
|
|
764
|
+
@conf.hsts = nil if @conf.hsts.empty?
|
|
751
765
|
end
|
|
752
766
|
end
|
|
753
767
|
|
|
@@ -887,7 +901,8 @@ def saveconf_csrf_protection
|
|
|
887
901
|
if (check_method & 2 == 2 &&
|
|
888
902
|
(old_method & 2 == 0 || old_key != check_key))
|
|
889
903
|
@conf.save
|
|
890
|
-
|
|
904
|
+
# the path is sent as a Location header now, so no HTML escaping
|
|
905
|
+
raise ForceRedirect, "#{@conf.update}?conf=csrf_protection#{@cgi.referer ? '&referer_exists=true' : ''}"
|
|
891
906
|
end
|
|
892
907
|
end
|
|
893
908
|
err
|
|
@@ -169,6 +169,21 @@ add_conf_proc( 'default', 'Site information', 'basic' ) do
|
|
|
169
169
|
<option value="SAMEORIGIN"#{" selected" if @conf.x_frame_options == 'SAMEORIGIN'}>Permit in same domain</option>
|
|
170
170
|
<option value="DENY"#{" selected" if @conf.x_frame_options == 'DENY'}>Deny</option>
|
|
171
171
|
</select></p>
|
|
172
|
+
|
|
173
|
+
<h3 class="subtitle">Referrer Policy</h3>
|
|
174
|
+
<p>Controls how much referrer information the browser sends when following links from your diary to other sites. The default matches the browser's standard behavior.</p>
|
|
175
|
+
<p><select name="referrer_policy">
|
|
176
|
+
<option value="strict-origin-when-cross-origin"#{" selected" if @conf.referrer_policy == 'strict-origin-when-cross-origin'}>Send origin only to other sites (default)</option>
|
|
177
|
+
<option value="same-origin"#{" selected" if @conf.referrer_policy == 'same-origin'}>Do not send to other sites</option>
|
|
178
|
+
<option value="no-referrer"#{" selected" if @conf.referrer_policy == 'no-referrer'}>Never send</option>
|
|
179
|
+
</select></p>
|
|
180
|
+
|
|
181
|
+
<h3 class="subtitle">Force HTTPS (HSTS)</h3>
|
|
182
|
+
<p>Sends the Strict-Transport-Security header on HTTPS responses so browsers keep using HTTPS afterwards. Leave disabled if your site is served over HTTP.</p>
|
|
183
|
+
<p><select name="hsts">
|
|
184
|
+
<option value=""#{" selected" unless @conf.hsts}>Disabled</option>
|
|
185
|
+
<option value="max-age=31536000"#{" selected" if @conf.hsts == 'max-age=31536000'}>Enabled (1 year)</option>
|
|
186
|
+
</select></p>
|
|
172
187
|
HTML
|
|
173
188
|
end
|
|
174
189
|
|
|
@@ -196,6 +196,21 @@ add_conf_proc( 'default', 'サイトの情報', 'basic' ) do
|
|
|
196
196
|
<option value="SAMEORIGIN"#{" selected" if @conf.x_frame_options == 'SAMEORIGIN'}>同一ドメインなら許可する</option>
|
|
197
197
|
<option value="DENY"#{" selected" if @conf.x_frame_options == 'DENY'}>禁止する</option>
|
|
198
198
|
</select></p>
|
|
199
|
+
|
|
200
|
+
<h3 class="subtitle">Referrerポリシー</h3>
|
|
201
|
+
<p>日記内のリンクをたどって他のサイトへ移動するときに、ブラウザが送信するReferrerの範囲を指定します。標準の設定はブラウザの既定動作と同じです。</p>
|
|
202
|
+
<p><select name="referrer_policy">
|
|
203
|
+
<option value="strict-origin-when-cross-origin"#{" selected" if @conf.referrer_policy == 'strict-origin-when-cross-origin'}>他サイトへはURLの先頭部分のみ送信する(標準)</option>
|
|
204
|
+
<option value="same-origin"#{" selected" if @conf.referrer_policy == 'same-origin'}>他サイトへは送信しない</option>
|
|
205
|
+
<option value="no-referrer"#{" selected" if @conf.referrer_policy == 'no-referrer'}>常に送信しない</option>
|
|
206
|
+
</select></p>
|
|
207
|
+
|
|
208
|
+
<h3 class="subtitle">HTTPSの強制(HSTS)</h3>
|
|
209
|
+
<p>HTTPSでアクセスされたときに、以後もHTTPSの使用をブラウザに強制するStrict-Transport-Securityヘッダを送出します。HTTPで運用しているサイトでは無効のままにしてください。</p>
|
|
210
|
+
<p><select name="hsts">
|
|
211
|
+
<option value=""#{" selected" unless @conf.hsts}>無効</option>
|
|
212
|
+
<option value="max-age=31536000"#{" selected" if @conf.hsts == 'max-age=31536000'}>有効(期間1年)</option>
|
|
213
|
+
</select></p>
|
|
199
214
|
HTML
|
|
200
215
|
end
|
|
201
216
|
|
data/lib/tdiary/plugin.rb
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module TDiary
|
|
2
|
+
module Rack
|
|
3
|
+
#
|
|
4
|
+
# class ErrorHandler
|
|
5
|
+
# catches exceptions leaked from the downstream app, reports the
|
|
6
|
+
# class, message and backtrace to rack.errors, and replaces the
|
|
7
|
+
# response with a plain 500 that does not expose the details to
|
|
8
|
+
# the client.
|
|
9
|
+
#
|
|
10
|
+
class ErrorHandler
|
|
11
|
+
def initialize( app )
|
|
12
|
+
@app = app
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call( env )
|
|
16
|
+
@app.call( env )
|
|
17
|
+
rescue Exception => e
|
|
18
|
+
self.class.report( env['rack.errors'], e )
|
|
19
|
+
[500, { 'content-type' => 'text/plain' }, ["500 Internal Server Error\n"]]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.report( errors, e )
|
|
23
|
+
errors.puts "#{e.class}: #{e.message}"
|
|
24
|
+
( e.backtrace || [] ).each {|line| errors.puts "\t#{line}" }
|
|
25
|
+
errors.flush
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Local Variables:
|
|
32
|
+
# mode: ruby
|
|
33
|
+
# indent-tabs-mode: t
|
|
34
|
+
# tab-width: 3
|
|
35
|
+
# ruby-indent-level: 3
|
|
36
|
+
# End:
|
data/lib/tdiary/rack.rb
CHANGED
data/lib/tdiary/request.rb
CHANGED
|
@@ -5,8 +5,9 @@ module TDiary
|
|
|
5
5
|
|
|
6
6
|
# the @cgi object handed to plugins: a facade over this request.
|
|
7
7
|
# Endpoints behind a web server (CGI/FCGI) set tdiary.static_assets in
|
|
8
|
-
# the env to get the base CGICompat
|
|
9
|
-
#
|
|
8
|
+
# the env to get the base CGICompat. The RackCGI/CGICompat split only
|
|
9
|
+
# serves third-party plugins that check @cgi.is_a?(RackCGI); in-repo
|
|
10
|
+
# code reads the flag through RequestExtension#static_assets?.
|
|
10
11
|
def cgi_compat
|
|
11
12
|
@cgi_compat ||=
|
|
12
13
|
if env['tdiary.static_assets']
|
|
@@ -15,6 +16,15 @@ module TDiary
|
|
|
15
16
|
::RackCGI.new( self )
|
|
16
17
|
end
|
|
17
18
|
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
# CGI splits the query string on ';' as well as '&', and tDiary's own
|
|
23
|
+
# edit links (00default.rb, edit_today.rb) still use ';'; Rack 3
|
|
24
|
+
# dropped the ';' separator, so restore it for Rack::Request#params
|
|
25
|
+
def parse_query( qs, d = '&' )
|
|
26
|
+
super( qs, '&;' )
|
|
27
|
+
end
|
|
18
28
|
end
|
|
19
29
|
end
|
|
20
30
|
|
data/lib/tdiary/server.rb
CHANGED
|
@@ -12,6 +12,28 @@ module TDiary
|
|
|
12
12
|
require 'webrick/accesslog'
|
|
13
13
|
require 'tempfile'
|
|
14
14
|
|
|
15
|
+
# WEBrick's CGI runner clears the environment of the CGI child process
|
|
16
|
+
# before exec'ing it, so the child cannot find the gems the server itself
|
|
17
|
+
# runs with. Hand the RubyGems and Bundler locations back to it.
|
|
18
|
+
module CGIEnvironment
|
|
19
|
+
def meta_vars
|
|
20
|
+
super.merge( {
|
|
21
|
+
'HOME' => ENV['HOME'],
|
|
22
|
+
'GEM_HOME' => Gem.dir,
|
|
23
|
+
'GEM_PATH' => Gem.path.join( File::PATH_SEPARATOR ),
|
|
24
|
+
'BUNDLE_GEMFILE' => ENV['BUNDLE_GEMFILE'],
|
|
25
|
+
}.compact )
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class CGIHandler < WEBrick::HTTPServlet::CGIHandler
|
|
30
|
+
def do_GET( req, res )
|
|
31
|
+
req.extend( CGIEnvironment )
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
alias do_POST do_GET
|
|
35
|
+
end
|
|
36
|
+
|
|
15
37
|
class << self
|
|
16
38
|
def run( option )
|
|
17
39
|
@@server = new( option )
|
|
@@ -38,9 +60,9 @@ module TDiary
|
|
|
38
60
|
CGIInterpreter: WEBrick::HTTPServlet::CGIHandler::Ruby
|
|
39
61
|
)
|
|
40
62
|
@server.logger.level = WEBrick::Log::DEBUG
|
|
41
|
-
@server.mount("/",
|
|
42
|
-
@server.mount("/index.rb",
|
|
43
|
-
@server.mount("/update.rb",
|
|
63
|
+
@server.mount("/", CGIHandler, TDiary.root + "/index.rb")
|
|
64
|
+
@server.mount("/index.rb", CGIHandler, TDiary.root + '/index.rb')
|
|
65
|
+
@server.mount("/update.rb", CGIHandler, TDiary.root + "/update.rb")
|
|
44
66
|
@server.mount("/theme", WEBrick::HTTPServlet::FileHandler, TDiary.root + '/theme')
|
|
45
67
|
@server.mount("/js", WEBrick::HTTPServlet::FileHandler, TDiary.root + '/js')
|
|
46
68
|
end
|
data/lib/tdiary/version.rb
CHANGED