2007年 09月 26日

環境に一切干渉できない eval

#!ruby -Ku

# クラス化して Module.new.instance_eval するようにしてみる。
# まだなんかあるかなぁ……

class SafeEval

	def safe_eval(code, tm=1)
		result = nil
		tg = nil
		th = Thread.start do
			# スレッドグループを作り、
			# 新たなスレッドはすべてこれに所属させる。
			tg = ThreadGroup.new.add(Thread.current)
			$SAFE  = 4
			result = Module.new.instance_eval(code)
		end.join(tm)
		# 生成されたスレッドをすべて削除
		tg.list.each {|t| t.kill }
		raise TimeoutError unless th # タイムアウトした場合 Thread は nil を返す
		result
	end

	alias eval safe_eval

end

if $0 == __FILE__
	require "test/unit"
	class SafeEvalTest < Test::Unit::TestCase

		def setup
			@t = SafeEval.new.taint
		end

		def test_safe
			assert_raise(SecurityError) do
				@t.safe_eval("puts ''")
			end

			assert_raise(SecurityError) do
				@t.safe_eval("$foo = :foo")
			end

			assert_nothing_raised(SecurityError) do
				@t.safe_eval("def hoge; end")
			end

			@t.safe_eval <<-EOS
				def safe_eval(code)
					"Nice boat."
				end
			EOS
			assert_not_equal("Nice boat", @t.safe_eval("nil"))

		end

		def test_safe_access
			assert_raise(NoMethodError) do
				@t.safe_eval("@foo << :bar")
			end
			assert_equal(nil, @t.instance_variable_get(:@foo))

			assert_raise(NameError) do
				@t.safe_eval("@@foo")
			end
		end

	end
end

まだなんかあるかなぁ……
SafeEval クラスは毎回つかいすてる。
インスタンス変数は無名 Module でさよならする。
クラス変数は SafeEval クラスが untaint である限りつくれない。

chokan 更新

Eval はとりあえずオフにしたまま。

とりあえず改行をちゃんととりのぞくように
http://lab.lowreal.net/trac/changeset/879
invite されたときほいほいついていかないように
http://lab.lowreal.net/trac/changeset/880
operator に設定されたマスクからだけ invite をうけるように
http://lab.lowreal.net/trac/changeset/882
@もらったらくれた人の@を奪ってから@を捨てるプラグイン
http://lab.lowreal.net/trac/browser/chokan/trunk/plugins/always_no_op.rb

@うばうのは AutoOP でループしないようにだけど、普通は JOIN で処理してて大丈夫だろうから奪わなくてもいいかもしれない。チャンネル唯一のオペレータが chokan に@あげるとチャンネルのオペがいなくなる。

2007年 09月 25日

curses のメモ

じぶんはターミナルをほぼ全画面表示させているので、横幅が結構ながい。
そんなんで、ときどき右側にちょっと表示させたいなぁってことがあったりするのでそれのサンプル。

#!/usr/bin/env ruby

require "curses"
class Curses::Window
	def puts(*msgs)
		write(msgs.map {|m| m.to_s.chomp + "\n" }.join)
	end

	def write(str)
		@data ||= ""
		@data << str

		setpos(0, 0)
		l = maxy - 1
		out = @data.split(/\n/).last(l).join("\n") + "\n"
		addstr(out)
		refresh
		@data = @data.match(/(.*\n)*.*\n?\z/)[0] 
	end

	def sync=(*)
	end
end

Curses.init_screen
begin
	win1 = Curses::Window.new(Curses.lines, (Curses.cols / 2).to_i, 0, 0)
	win2 = Curses::Window.new(Curses.lines, (Curses.cols / 2).to_i, 0, (Curses.cols / 2).to_i+1)

	Curses.refresh
	
	$stdout = win1
	$stderr = win2
	
	load(ARGV.first, true)

ensure
	Curses.close_screen
end

$stdout と $stderr を画面半分ずつわけて表示させてみる。引数に ruby スクリプトをとる。
うえのをてきとうに double.rb とかで保存して http://lab.lowreal.net/trac/browser/c/mendoi/proxy.rb を実行させると、左にのっとりされたファイル、右にスキャンしたファイルが表示される。

(画面ちっちゃくして撮影)

$0 == __FILE__ やってるスクリプトはうごかないけど、とりあえず proxy.rb だけこうしたかった (ちゃんとのっとりできてるかわかりにくかった)

@data をちゃんとつめないとだめだ
http://lab.lowreal.net/trac/changeset/877

Tumblr のログイン支援

http://svn.coderepos.org/share/lang/javascript/userchrome/tumblr-multi.uc.js
ステータスバーに tumblr のアイコンがでる。クリックすると今までログインしたことのあるユーザ名が一覧表示され、選択するとそのアカウントでログインしたうえでブックマークレット発動
ログイン情報はパスワードマネージャから拾ってくるので保存されてないとつかえない。

chokan クラックされた

Eval と SimpleReply 系を併用してつかってる人がもしいたらすぐ Eval のほうを無効にしてください。任意の IRC コマンドが放てます。

IRCNet にいた chokan は一旦落とし、Eval をロードしない状態でうごかしています。てら迷惑な chokan
もっとセキュアな eval を考え中

kill してとめて main screen turn on / got signal とかいうから、あれもしかして SSH で入ってシェル見てんのとか思ったりして tail -f /var/log/auth.log したりとか……
でもぱっとみは chokan 経由でしかやってなかったっぽいし、なんで signal でとめたのがわかったのかわからない……彼らからするとみえないはずなんだけどなぁ。chokan のログはとってなくて (表示させてるだけで、追ったときは screen のバックログ検索) ふかくおえない……

chokan は tiarra 経由でつないでて、chokan.rb を殺しても IRCNet 側的にはなにもおきない (これは CTCP で彼らはしってた)。Eval 経由ではソケットへの書き込みは $SAFE 的に一切できないはずだから (できるなら SimpleReply を経由しないだろう)、直接そこからどうこうしたってわけではないと思う……

直接 chokan に対してセッションをはれていたわけではないはずだから、SEGV させてうんたらってのはできないはず。SEGV させたら Eval がもう動かないし

  • chokan.rb から任意の IRC コマンドが発行できる状態になっていた
  • freenode と ircnet につないでいたが IRCNet 以外ではとくになんもなかった
  • 他のチャンネルいくつかにも強制 JOIN していた。すべて IRCNet
  • http/https/ssh/ircd 以外のポートはルータの時点で閉じてる。
  • SSH のログで最後にアタックがあったのは 16:00 で、.net ドメイン (全て失敗) クラッカーは .at .ch だった。
  • SSH はそれから先 publickey でのおれのログインしかない。

直接セッションはらせる方法もあることはあるか……
DCCCache つかって CTCP SEND 投げて chokan に直接接続させて、ほげほげ? できんの?
とおもったけど、接続がきた時点で日付とか nick をふくめてファイルを生成しているのになんもできないからこれは使ってないっぽい。

2007年 09月 24日

canvas on Safari

Fx 用にかいたのを Safari でもうごくようにしたいメモ書き

  • createLinearGradient は canvas を appendChild してからじゃないと値かえさない
  • fillRect() でグラデーションえがけない。 beginPath(); rect(); fill() にわける。
2007年 09月 23日

ブックマークレットとかで、設定を先頭に書けるようにする

設定を分離するために

javascript:(function (url) {
   // hoge
})("http://example.com");

みたいにしたりするけど、最後に書くのがちょっとだるい。ので、次のようなのを考えてみた。

javascript:"http://example.com".replace(/.+/, function (url) {
  // hoge
});void("fumino");

ちょっと長くなるのでぎりぎりの場合はつかえないけど、設定が前にでてくるので書きかえやすい。スクリプト要素追加系だと、中身は共通なのでこっちのほうが新しくブックマークレットつくりやすい (ささいな手間といえばそうだけれど)

これを使うとスクリプト追加系は以下のように

javascript:"url".replace(/.+/,function(url,s){s=document.createElement("script");s.charset="utf-8";s.src=url;document.body.appendChild(s)});void("san");

javascript:"url".replace(/.+/, function(url, s) {
    s = document.createElement("script");
    s.charset = "utf-8";
    s.src = url;
    document.body.appendChild(s)
});void("moe");

わりとどうでもいいけど

var s=...

と書くかわりに、仮引数を使うことでなんか気持悪いスペースを消してみてる。

複数の引数をとりたいときも同じように書ける。ただしデータの変換は関数内部でやることになるし、パースも自分で正規表現を書くことになる。でもたいしたこと書かないから問題ないとおもう。

"2222 81".replace(/(\d+) (\d+)/, function(_, a, b) { alert(Number(a)+Number(b)) });void("二次元にいきたい");

zsh の bindkey -v (vi バインド) でモード表示するようにした


どっちだかわからなくて不安になるので (どうせ C-[ 連打するとはいえ) 検索したらすぐヒットした。http://www.zsh.org/mla/users/2002/msg00105.html

http://lab.lowreal.net/trac/changeset/871

でもこれだと毎回プロンプトだすときに INSERT とかでてうざったいので、preexec で前回表示したモード表示を消すようにしてみた。(数値きめうちなので、複数行入力するとおかしくなる。PREBUFFER とかつかえばいいのかな)

http://lab.lowreal.net/trac/changeset/872

でも preexec なので C-c とかやってプロンプトリセットしたりすると残ってしまう。

ほんとはプロンプトの下にだしたいのだけど、位置指定してほげほげしてると、INSERT -> NORMAL -> INSERT とかやったときひどいことになるので諦めた……screen の hardstatus に出すのがいいのかもしれないけど、なんかそれも違う気がしたので妥協

あと関係ないけど、C-p C-n がなぜかそのまま入力されてうざいので、それだけはバインドした。
http://lab.lowreal.net/trac/changeset/870 (bindkey -e; bindkey L ででてきた結果を適当につっこんだので ^O もバインドしてある。つかわない)

ML おってたらもっと簡単なのがあったのでそっちにへんこう
http://lab.lowreal.net/trac/changeset/873

zsh の補完

なんか exec zsh を毎回やらないとエラーでるようになった。

書く順番書けたらなおった。cmp 系はあとのほうに書かないといけないっぽいのかな

2007年 09月 21日

nsIRDFXMLSerializer で日本語を文字化けしないようにする。

http://nanto.asablo.jp/blog/2006/10/23/572458 を途中でやってあげた

var outputStream = {
	data: "",
	close : function () {},
	flush : function () {},
	write : function (buffer, count) {
		// 文字化け対策
		this.data += decodeURIComponent(escape(buffer));
		return count;
	},
	writeFrom : function (stream, count) {} ,
	isNonBlocking: false
};
var ser = Components.classes["@mozilla.org/rdf/xml-serializer;1"]
                    .createInstance(Components.interfaces.nsIRDFXMLSerializer);
ser.init(ds); // ds に DataSource がはいってる 
ser.QueryInterface(Components.interfaces.nsIRDFXMLSource).Serialize(outputStream);
alert(outputStream.data);