jiao Hiroshi, Shibata. My name is Hiroshi SHIBATA, please call me Hiroshi or SHIBATA. This jacket is my trademark and fighting armor. Today is same jacket.
and this is most important things. Second, running environments are traditional CGI and Rack. It means tDiary can run in all of application server. For example apache, passenger and unicorn. Third, it has pluggable mechanism. It mechanism is possibled by ruby meta-programming. this feature supports newbie rubyists.
the sf.net and used CVS. I joined tDiary developper team this year. First version supported Ruby-1.6.7. Please raise up your hands if you had used this version of Ruby?
Ruby needed to run the tDiary.” This phrase posted some contents in 2004. It means tDiary more famous lather than Ruby. Everyone knows tDiary in Japan.
changing occurred in this version. All of String have Encoding. tDiary was broken by encoding changes. It was so hard for us, and we have be supporting now.
= true unless @secure @options = {} eval( File::open( 'tdiary.conf' ) {|f| f.read }.untaint, b, "(tdiary.conf)", 1 ) # language setup @lang = 'ja' unless @lang begin This is part of tDiary’s code. tDiary configuration was written by Ruby code. it’s not by yaml and json.
Array's contents are String # of Ruby. Though these Strings are converted to Regular Expression # of Ruby when compared, you can't use Regexp of Ruby. @no_referer = [ '^' + Regexp.quote( base_url ), # Your diary '^http://localhost[:/]', '^http://192.168.', '^http://172.1[6789]', '^http://172.2[0-9]', '^http://172.3[01]', '^http://10.', ] # URLs which are only recorded into Today's Link (Regular Expression) # @only_volatile is an array of URLs to record into only Today's Link. # When a referer match to this list, it will be recoreded to volatile # list. This list will be cleared when you make new text in new day. # Specify @only_volatile same style of @no_referer. @only_volatile = [ ] # The rules which convert the specified URL to the word (Regular Expression) # @referer_table is configured so that readable URLs are shown in This is example of tdiary configuration file. If you try to customize tDiary behavior, you should write method definitions, variable settings and more into “tdiary.conf”. It’s very useful.
} (class << self; self; end).class_eval { attr_accessor *names } end def configure_bot_pattern bot = ["bot", "spider", "antenna", "crawler", "moget", "slurp"] bot += @options['bot'] || [] @bot = Regexp::new( "(#{bot.uniq.join( '|' )})", true ) end Next point is class_eval. tDiary uses classic “cgi.rb” and creates CGI instance per all requests. CGI instance have a configuration instance. It needs access mechanism for tDiary’s core and plugins. class_eval make configuration instance possible to access it.
File::dirname( file ) + "/#{@conf.lang}/" + File::basename( file ) open( res_file.untaint ) do |src| instance_eval( src.read.untaint, "(plugin/ #{@conf.lang}/#{File::basename( res_file )})", 1 ) end @resource_loaded = true rescue IOError, Errno::ENOENT end File::open( file.untaint ) do |src| instance_eval( src.read.untaint, "(plugin/ #{File::basename( file )})", 1 ) end end The i18n of tDiary use Ruby code. this is same the case of configuration files. tDiary doesn’t use i18n gem! In past, tDiary include chinese language. but we dropped it, because we have no maintainer.
security issue.support two things. one, share hosting environment. imagine of you made cgi in shared hosting environment. that cgi can use code written by other people. If this code is exploit code. How do you protect it?
res_file )})", 1 ) end @resource_loaded = true rescue IOError, Errno::ENOENT end File::open( file.untaint ) do | src| instance_eval( src.read.untaint, "(plugin/ #{File::basename( file )})", 1 ) end end I talk overview of $SAFE mechanism. $SAFE mechanism makes all object taint. Once you use $SAFE, you can’t use tainted object in some function. If you want to use tainted objects, you should call “untaint” method.
`initialize': Insecure operation - initialize (SecurityError) from -e:1 $SAFE level 1 disallow “File.open” with tainted strings. If you want to open with ARGV[0] string. you should call “untaint”.
operation at level 4 (SecurityError) from -e:1:in `<main>' % ruby -e '$SAFE=1; eval("p :foo".untaint)' :foo $SAFE level 4. If you use untainted strings with eval, this level disallow using it. tDiary customization is handled with eval and $SAFE mechanism.
= 4 ) result = nil if $SAFE < level then Proc.new { $SAFE = level result = yield }.call else result = yield end result end module_function :safe end It’s protips. If you use different $SAFE level in same code. you need to use “Proc#new” and “Proc#call”. tDiary use this procedure when running with shared environment.
from untrusted load paths. [ruby-dev:44541] [Bug #5279] * transcode.c (load_transcoder_entry): ditto. assume system default tmpdir safe. [ruby-dev:42089] http://bugs.ruby-lang.org/issues/3733 fixed r29209: assume system default tmpdir safe. [ruby-dev:42089] http://bugs.ruby-lang.org/issues/1115 * load.c (rb_require_safe): raises when the path to be loaded is tainted. [ruby-dev:37843] I've never seen that other people are using $SAFE feature. therefore $SAFE feature is very buggy.
ruby -e '$SAFE=1;File.expand_path(".".taint)' -e:1:in `expand_path': Insecure operation - expand_path (SecurityError) from -e:1:in `<main>' This defects. if you use “tmpdir” running with $SAFE level 4, Ruby raised exception.
untrusted load paths. [ruby-dev:44541] [Bug #5279] * transcode.c (load_transcoder_entry): ditto. assume system default tmpdir safe. [ruby-dev:42089] % ruby -e ‘$SAFE = 3; "a".encode("UTF-16")’ -e:1:in `encode': Insecure operation - encode (SecurityError) from -e:1:in `<main>' In this report. If you run some code with $SAFE level 4, and not with calling “encode”. Ruby is raised exception. I already talked about all of String has Encoding in Ruby 1.9. This defects is important, because anyone never use String#encode with $SAFE level 4 in Ruby 1.9
dropped out $SAFE feature in 2.1. We accept it. so tDiary need to change with rubies. The Internet environment is changing now. people doesn’t use shared hosting server. they use PaaS like a sqale and heroku.
in test environment, your hobby code should run with Ruby-2.0. I think that programmer have hobby code. tDiary is hobby code. Matz said “Ruby is hobby code!” too.
[Bug #6781] reported by hsbt (Hiroshi SHIBATA). http://bugs.ruby-lang.org/issues/5952 * io.c (argf_next_argv): reset ARGF.next_p on ARGV.replace. r34409 breaks replacing ARGV. [ruby-dev:45160] [Bug #5952] http://bugs.ruby-lang.org/issues/7040 * ext/zlib/zlib.c (zstream_run_func): don't call inflate() when z->stream.avail_in == 0. it return Z_BUF_ERROR. but deflate() could be called with z->stream->avail_in == 0 because it has hidden buffer in z->stream->state (opaque structure). fix for gem install error. [ruby-dev:46149] [Bug #7040] I discovered some defects in ruby-trunk. One of these defects is ruby-trunk can’t install some gems like libv8. Today’s ruby is fixed by my reports.
cgi.rb. I thought this feature broke backward compatibility. I reported it for ruby-core. In this result, this feature reverted. You need to run your code with early version of Ruby. and report defects, behavior change and new feature. If you detect behavior change after code freeze, it’s too late.
so. this picture is one of scene in rubyconf. matz, ko1 and JRuby guys and many commiter and people discussion “refinements” Your report and proposal of new feature are making ruby!