2005-07-01 (Fri) [長年日記]
_ JAFと警察
通勤途中、前の車が信号が青になっても進まないのでクラクションを 鳴らしたら、運転手が降りてきた。 「しまった、やられる」と思ってびくびくしていると、車が故障 したのでJAFを呼びたい、携帯を貸してほしい、とのこと。
気安く応じたものの、なかなか電話が終わらない。 片道2車線ではあるが、後ろを見ると大渋滞である。 どうもJAFに入っておらず、お金も持ってないそうで、JAFには 来てもらえないらしい。 「へえ、JAFって後払いできないんだ」 と思いつつ「警察に電話してみたらどうですか」と勧めたが、 やっぱり来てもらえないらしい。事故じゃなくてただの故障だと 対応できないとのこと。
最後は、自分が賢察に「そんなこと言ったって こんなとこに車が止まってたら交通の邪魔だから、レッカーか何かで 移動するくらいしてくださいよ」ということで、何とか来てもらう ことにしてその場を去った。
その後どうなったのかなあ。
_ Subversionへの移行
ruby-devとruby-coreで提案してみたが、ruby-coreの方は「いや、 あれがいい」とか「これがいい」とか出て来る、出て来る。
だんだん、もうCVSでいいやって気分になって来たな。 Subversionに移行した方がよいと思う方はruby-coreでがんばってください。
2005-07-02 (Sat) [長年日記]
_ 新しいブロックパラメータの文法
{} でくくったブロックの最初には () でくくった式が来ちゃイケナイってのは、無茶苦茶でかい仕様変更だから無理なんだろうなぁ。
[だいありーより引用]
メソッドの引数に合わせて *1、 {やdoとブロックパラメータの(の間に スペースを許さないようにするというのはどうだろう。
method(x, y) do(a, b) #... end method(x, y) {(a, b) #... }
のような場合は、(a, b)をブロックパラメータとして扱って、
method(x, y) do (a, b) #... end method(x, y) { (a, b) #... }
のような場合は、(a, b)をグルーピングされた式として扱う。
*1 現状ではまだ警告だけど。
_ Collaboa
Rubyで書かれたTracのようなもの。 しかし、ほんとにそっくりだなあ。 HTMLやCSSの流用をしてたりするんだろうか。
とりあえず、ximapdで試してみた。
<URL:http://projects.netlab.jp/ximapd/dev/>
なぜかFastCGIだとbin/ximapdのブラウズ時にエラーになるので CGIにしている。遅い...。
2点ほど細かい問題を見つけたので、New Ticketしておいた。
_ SubversionのRuby binding
Collaboaには、SubversionのRuby bindingがいるが、 sargeのSubversionは1.1.4でRuby bindingはない*1 ので、Subversion 1.2.0を取って来て、Ruby bindingだけインストール。
$ tar jxvf subversion-1.2.0.tar.bz2 $ cd subversion-1.2.0/ $ ./configure --with-apr=/usr/bin/apr-config --with-apr-util=/usr/bin/apu-config --with-neon=/usr/bin/neon-config $ make check-swig-rb # make install-swig-rb
ちなみに、Subversion 1.2.0はSubversion 1.1.4とAPI互換らしい。 新しい関数の追加だけ、というのは素晴らしいな。
*1 sidにもないか。
2005-07-03 (Sun) [長年日記]
_ 散髪
娘と散髪に。 今日は床屋で一緒に切ってもらった。
自分は仰向けで頭を洗われるのが嫌いなのだが、娘は大丈夫らしい。 床屋で仰向けなのは邪道だと思う(自分はうつぶせでやってもらった)の だが、最近の床屋が仰向けで頭を洗うのは男の髪が長くなって来た せいだろうか。
2005-07-05 (Tue) [長年日記]
_ Thunderbirdでフォルダを開いた時に自動的にダウンロードしない設定
ThunderbirdはIMAPフォルダを開いただけで、勝手にそのフォルダの 全メールのダウンロードを始めてしまうので、spamフォルダを開くとなかなかつらい。
どなたか勝手にダウンロードをさせない設定を知っていたら教えてくださいm(..)m
mail.server.default.download_on_biffという設定は見つけたけど、 これは
新着確認で新しい message を download するなら true、user に新しい mail があることを通知するなら false。
ということで、ちょっと違うんだよなあ。
2005-07-06 (Wed) [長年日記]
_ CollaboaのBrowserで日本語のテキストを表示する
ximapdをいじるつもりが、なぜかCollaboaをハックしていた。 Browserでiconvを通すようにしたので、以下のようにちゃんと日本語が表示できるようになった。
<URL:http://projects.netlab.jp/ximapd/dev/repository/file/trunk/README.ja>
svk便利だなあ。
_ --rebuild-index
寝入りばなにDSAで起こされたついでに、--rebuild-indexを実装。 Rastのインデックスが壊れたらお試しください。
2005-07-14 (Thu) [長年日記]
_ created_on/updated_on
created_onフィールドおよびupdated_onフィールドは必須ではありませんが、これらのフィールドを指定すると、Railsが自動的に保持します。
[IBM dW : linux :Ruby on RailsによるWebアプリケーションの高速開発 - Japanより引用]
そんな機能があったのか。
_ サイトリニューアル
Railsでサクっと作ってみた。 コンテンツはBlueClothによるMarkdown記法で書いているのだが、 Markdownってテーブルないんだっけ。 結局テーブルはHTMLで書いてしまった。 あと、言語の切替えはセッション管理でやっているのだが、これだと Googleが日本語のページを拾ってくれないような気がする。 URLにjaとかenとかが入るようにしないとだめだろうか。
実はこれのせいで本体の開発がぜんぜん進んでない。 とりあえず、0.0.2を出しとくかなあ。
_ 強い型の言語の気持ちよさ
前日にビルド環境がなかったので、適当に書いていたコードが やはりコンパイルに失敗した。 とりあえず、コンパイルが通るようにしたところ、一発で動作。 こういう時の気持ち良さには、Rubyにはないものがあるな。
書いたコードが一発でテストに通った時がそれに近いけど、 自分で書いたテストには何となく不安があるので、通ったら 通ったで「本当にだいじょうぶかなあ」という気分になる。 結局テストをきちんと書けってことなんだけど、いろんなケースを 網羅するテストをいっぱい書くのはつらいんだよなあ。
2005-07-15 (Fri) [長年日記]
_ CSRF対策
0.13.0にもCSRF対策のコードはとくにないようだ。 MLの議論を追ってなかったのだが、結局アプリケーション側で対策する べしということだろうか。
まず、ApplicationControllerとApplicationHelperに以下のような記述をしておく。
app/controller/application.rb:
class ApplicationController < ActionController::Base private def validate_session if @params[:session_id_validation] == @session.session_id return true else render(:text => SESSION_VALIDATION_FAILED_HTML, :status => "403 Forbidden") return false end end SESSION_VALIDATION_FAILED_HTML = <<EOF <html> <head> <title>403 Forbidden</title> </head> <body> <h1>403 Forbidden</h1> <p> Session validation failed. </p> </body> </html> EOF end
app/helpers/application_helper.rb:
module ApplicationHelper def secure_form_tag(*args) return start_form_tag(*args) + "\n" + hidden_field_tag("session_id_validation", @session.session_id) end end
あとは、保護が必要な各フォームでstart_form_tagの代りにsecure_form_tagを 使い、
app/views/<controller_name>/edit.rhtml:
<h1>Edit</h1> <%= secure_form_tag :action => 'update', :id => @model_name %> <%= render_partial 'form' %> <%= submit_tag 'Edit' %> <%= end_form_tag %> <%= link_to 'Show', :action => 'show', :id => @model_name %> | <%= link_to 'Back', :action => 'list' %>
各コントローラの必要なアクションにフィルタを設定する。
app/controllers/<controller_name>_controller.rb
class <ControllerName>Controller < ApplicationController before_filter :validate_session, :only => [:create, :update, :destroy] #... end
こんなもんかなあ。
あと、scaffoldはGETでdestoryするようなコードを出力するので、 確認画面を用意してPOSTでdestroyするようにする必要がある。
_ Login GeneratorのSession Fixation Attack対策
今度はSession Fixation Attack(セッション固定攻撃)対策。
RailsはデフォルトでセッションIDを発行するようになっているが、 Login Generatorが生成するコードは、どうも認証後も同じセッションID を使っているようだ。
def login case @request.method when :post if @session[:user] = User.authenticate(@params[:user_login], @params[:user_password]) flash['notice'] = "Login successful" redirect_back_or_default :action => "welcome" else flash.now['notice'] = "Login unsuccessful" @login = @params[:user_login] end end end
このため、Session Fixation Attackの危険性があると思われる。
これを回避するには以下のようにセッションをリセットしてやればよい。
def login case @request.method when :post user = User.authenticate(@params[:user_login], @params[:user_password]) if user return_to = @session[:return_to] @request.reset_session @session = @request.session @session[:user] = user @session[:return_to] = return_to if return_to flash['notice'] = "Login successful" redirect_back_or_default :controller => "page", :action => "list" else flash.now['notice'] = "Login unsuccessful" @login = @params[:user_login] end end end
_ クッキーのパス
Railsではクッキーのパスはデフォルトで/に設定されるようだ。 これは/以外の場所(たとえば/ximapd)で運用する場合は望ましくない。
変更するには以下のようにconfig/environment.rbの末尾に記述すればよい。
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_path] = "/ximapd"
_ セッションファイルの作成場所
Railsではセッションファイルの作成場所はデフォルトで/tmpになる。 *1
/tmpの直下にセッションファイルを作るのはあまり好ましくない。 なぜなら、cronなどで削除した際に、同じファイル名で偽物のセッションファイルを作成できてしまうからだ。
変更するには以下のようにconfig/environment.rbの末尾に記述すればよい。
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:tmpdir] = File.expand_path("session", RAILS_ROOT)
もちろん、ディレクトリのパーミッションには注意が必要。 現在のCGI::Sessionでは、ファイル名からセッションIDを推測できないように なっているが、Railsの実行ユーザ以外はアクセスできないようにしておいた方が いいだろう。
*1 実際には環境による。
_ TrackBack [http://shugo.net/jit/20050716.html#p01 Journal InTime [Rub..]
2005-07-16 (Sat) [長年日記]
_ Login GeneratorのSession Fixation Attack対策(2)
これを回避するには以下のようにセッションをリセットしてやればよい。
[Journal InTime - CSRF対策 , Login GeneratorのSession Fixation Attack対策 , クッキーのパス , セッションファイルの作成場所より引用]
某所でセッションデータは引き継ぎたいという話があったのでちょっと改良。
def login case @request.method when :post user = User.authenticate(@params[:user_login], @params[:user_password]) if user @session[:user] = user data = @session.instance_variable_get(:@data) @request.reset_session @session = @request.session for key, val in data @session[key] = val end flash['notice'] = "Login successful" redirect_back_or_default :controller => "page", :action => "list" else flash.now['notice'] = "Login unsuccessful" @login = @params[:user_login] end end end
もうちょっとマシな方法はないものか。
_ Login GeneratorのSession Fixation Attack対策(3)
しつこいようですが。
RailsではクッキーでしかセッションIDは渡されないので、session fixation は難しいのではないかという話がある。
しかし、たとえば、ホスティングサービスなどで、同一ドメイン上に信頼 できない他のウェブアプリケーションが存在する場合などは危険だ。 また、他のXSS脆弱性との合わせ技といったことも考えられるので、 対策はしておいた方がよいと思う。
2005-07-20 (Wed) [長年日記]
_ Rubyist のための他言語探訪 【第 1 回】 Python
次回は、Ruby に影響を与えた言語の一つ、CLU を紹介する予定です。 お楽しみに!
[Rubyist Magazine - Rubyist のための他言語探訪 【第 1 回】 Pythonより引用]
おお。
_ ECMAScript 4 Namespaces
今さらながらECMAScript 4のnamespaceの仕様を勉強。 ちょっとややこしいのが、x.nのようなプロパティ参照によって、どのように プロパティ(JavaScriptだとメソッドもプロパティ)が検索されるか。
まず、すべてのプロパティはq::nCのように修飾された名前を持つ。 ここで、qはnamespace、nは識別子、Cはクラスである。
次に、xを評価するとインスンスになるような式、Σをプロパティ参照を含むすべてのスコープの集合、QをΣのスコープでuseされているすべてのnamespaceの集合とする。
x.nのようにnamespaceを明示せずにプロパティを参照した場合、次のような探索が行われる。
- Aを、xが少なくとも一つのq::nA(qはQの任意の要素)という プロパティを持つ、最も派生していない(Objectに近い)クラスとする。 もし、そのようなプロパティがなければエラー。
- Q'を、Qに属し、xがq::nAというプロパティを持つすべてのnamespaceの集合とする。
- Pを、xのq::n(qはQ'の要素)というプロパティのうち最も派生的なすべての プロパティの集合とする。
- もし、Pがただ一つの要素pを持つ、あるいはPのすべての要素が一つのプロパティp の別名である場合、pを選択する。それ以外の場合はエラー。
興味深いのは、まず最もObjectに近いクラスに定義されたプロパティを探して、 namespaceの候補を絞りこむ点。 同じ識別子を持つプロパティでも、起源となるクラスによって区別することが できるということか。
あと、namespaceに関しては、
# String#lengthの定義 class String { function length() { ... } } # jcodeというnamespaceの定義 namespace jcode # jcodeにString#lengthを定義 class String { jcode function length() { ... } } # MyString#lengthを定義 class MyString { function length() { ... } } # jcodeの使用を宣言 use jcode s = new MyString("あいうえお") len = s.length()
とした時に、s.length()が呼び出すのが、jcodeのString#lengthなのか、 MyString#lengthなのか、というのが疑問だった。 ECMAScriptでは、デフォルトのnamespaceはpublicというnamespaceで、 明示的にuseしなくても利用できるらしい。 ということは、MyString#lengthが呼び出されるのだろうか。
2005-07-21 (Thu) [長年日記]
_ 2.0.2にアップデート
そして、tDiaryQuoteが使えなくなった。
Refererのチェックをしないようにして、csrf_protection_keyを tDiaryQuoteで渡せるようにすればいいかな。
_ tDiaryQuoteのPOST対応
とりあえず、手もとでは上記の修正で動いたけど、csrf_protection_keyをGETで送っているので、プレビュー画面から外部へのリンクをたどるとRefererでcsrf_protection_keyが洩れてしまう。
これを防ぐにはPOSTにすればいいんだけど、どうやればいいのかわからず。 ちなみに現状は、
updateUrl += "?old=" + old + ";year=" + year + ";month=" + month + ";day=" + day + ";title=" + ";body=" + encodeURIComponent(body) + ";plugin_tb_url=" + encodeURIComponent(pingUrl) + ";plugin_tb_section=" + ";plugin_tb_excerpt=" + ";appendpreview=%A5%D7%A5%EC%A5%D3%A5%E5%A1%BC" + ";csrf_protection_key=" + encodeURIComponent(csrfProtectionKey); var newTab = browser.addTab(updateUrl); browser.selectedTab = newTab;
こんな感じ。
_ lighttpd doesn't cope with 100-continue
lighttpdは
Expect: 100-continue
というへッダがあるとリクエストを受け付けてくれないので、.NETから ActionWebServiceを使うためには、以下のようにGetWebRequest()を オーバーライドしないといけない、という話。
using System; using System.Net; [System.Web.Services.WebServiceBinding(Name="PostPort",Namespace="urn:ActionWebService"), System.Diagnostics.DebuggerStepThroughAttribute(), System.ComponentModel.DesignerCategoryAttribute("code")] public class BlaBlaService : Service { protected override WebRequest GetWebRequest(Uri uri) { HttpWebRequest request = (HttpWebRequest) base.GetWebRequest(uri); ServicePoint servicePoint = request.ServicePoint; // lighttpd doesn't cope with 100-continue servicePoint.Expect100Continue = false; return request; } }
_ rast extension
なんてものを作ったらウケるだろうか。
class Article < ActiveRecord::Base has_rast_index :title has_rast_index :body has_rast_index :updated_on end
としておくだけで勝手にRastのインデックスに登録してくれて、 検索する時は、
articles = Article.find_by_rast('ふが') articles = Article.find_by_rast(['title : ?', 'ほげ'], :order => "updated_on")
だけでいいとか。
2005-07-22 (Fri) [長年日記]
_ acts_as_rast_indexed
とりあえず、サクっと作ってみた。 効率もtransactionも気にしない。
まず、rast_indexed.rbをlib/active_record/acts/以下に置く。
次にconfig/environment.rbに
require "active_record/acts/rast_indexed" ActiveRecord::Base.class_eval do include ActiveRecord::Acts::RastIndexed end
と書いて、準備完了。
デフォルトではRAILS_ROOT/index/RAILS_ENV/以下にインデックスを作るが、 ActiveRecord::Acts::RastIndexed.configurations=で設定もできる。
あとは、モデルに
class Page < ActiveRecord::Base acts_as_rast_indexed end
のように書くだけで使える。
具体的にはこんな感じ。
page = Page.new(:name => "abc", :body => "This is abc") page.save pages = Page.find_by_rast(["body : ?", "abc"])
fixturesを使えるようにするにはtest/test_helper.rbに以下のおまじないを。
class << Fixtures alias create_fixtures_without_rast_index create_fixtures def create_fixtures_with_rast_index(fixture_directory, *table_names) result = create_fixtures_without_rast_index(fixture_directory, *table_names) for table_name in table_names.flatten table_class_name = Inflector.classify(table_name) table_class = Object.const_get(table_class_name) begin table_class.rebuild_rast_index rescue NoMethodError end end return result end alias create_fixtures create_fixtures_with_rast_index end
_ TrackBack [http://d.hatena.ne.jp/babie/20050729#p4 遅レス。 [Ruby][Rails]..]
_ ささだ [賢察?]
_ shugo [もう、いじわる。]