偶然の産物だったけどうまく動いている。
ピエゾ素子で作った振動センサーと、サーボモーターでドアをあけるやつ(最近Arduinoで実装しなおした)をLinda RocketIOで接続した。
もともとドア周辺の人間の歩行をセンシングしたくてセンサーを置いてみたのだけど、ドアのある場所をうまくノックすると反応していたのでノックで電子錠を開けれるようにした
これ
AndroidとNFCで研究室の鍵を開けるシステムができた
のどすこい認証バージョン
たぶん大丈夫だと思うんだけどヤバかったら教えて下さい。
(皆様からの温かいトマホーク(2)(3)によるとやっぱダメなようです)
要件
– ブラウザでRubyのコード書かせて、サーバーに保存してサーバーで実行したい– 危険な事はされたくない。ファイルへのアクセスやコマンドの実行、やたら時間のかかる処理など
– 安全に実行できたらコードの返り値を取得したい。コードが危険だったらエラーを取得したい。
– 危険な事されても、コード実行しているプロセスは終了しないでエラーをブラウザに返したい。
– コードはWebサーバーと同じプロセスで実行したい
調査
ということで調べていたらsafelevelを使えばいいらしい– Programming Ruby: The Pragmatic Programmer's Guide
– Rubyのセーフレベル4環境とその使い方 – ¬¬日常日記
$SAFEに0〜4までの数値を入れるとセーフレベルが変化する。Ruby起動時は0。
4(最高)の時はファイル操作やコマンド実行、標準出力もできなくなる。
一度上げたセーフレベルは下げれないが、Threadを作ってその中でセーフレベルを上げればThread外はセーフレベル0のままになるのと、
セーフレベル0の時にProcオブジェクトを作ればセーフレベル0環境をThread内に持ってこれるのを利用すれば、要件は満たせそうだ。
できた
このSandBoxクラスを使えば安全に実行できる。SandBox.eval(コード, コールバック)で実行する。
コールバックでコードの実行結果か例外オブジェクトが返ってくる。
sandbox.rb
require 'timeout'
class SandBox
def self.eval(code)
throw ArgumentError, "callback not given" unless block_given?
result_or_error = nil
begin
Timeout::timeout 1 do
result_or_error = Thread.new do
$SAFE = 4
instance_eval code
end.value
end
rescue StandardError, SecurityError, Timeout::Error => e
result_or_error = e
end
yield result_or_error
end
end
## 安全なコードを実行
goodcode = File.open("goodcode.rb").read
SandBox.eval goodcode do |res|
puts "-- goodcode.rb --"
p res
end
## 危険なコードを実行
badcode = File.open("badcode.rb").read
SandBox.eval badcode do |res|
puts "-- badcode.rb --"
p res
end
安全なコード(goodcode.rb)と危険なコード(badcode.rb)を実行してみた。
goodcode.rb – ちょっと計算して値を返しているだけなので安全
"cool!" * 10
gadcode.rb – ファイルアクセスや標準出力をしていて危険
File.delete "./hoge" if File.exists? "./hoge" # ファイル削除
puts "this is bad code" # 標準出力
system "ls" # コマンド実行
1+2*3/4 # ふつうの計算
sandbox.rb の実行結果
-- goodcode.rb --File.exists? の時点でエラーがでていた。もちろんputsもsystemもSecurityErrorになる。
"cool!cool!cool!cool!cool!cool!cool!cool!cool!cool!"
-- badcode.rb --
#<SecurityError: Insecure operation `eval' at level 4>
無限ループとか書かれても1秒でタイムアウトする。
このセーフレベル4環境を破るには、セーフレベル0を持っているコールバック関数を呼び出す必要があるのだが
ちょっと試した感じでは無理っぽいのでまあまあ安全だと思う。
ヤバイ処理を実行させられそうになったら即例外をコールバックするので、アプリも落ちないし俺の要求を満たしてる。
物凄いサイズのHash作られたりしたらダメかも。
GitHubのissue機能が好きすぎてヤバイので、最近90日以内に更新した全リポジトリのopenなissueを表示するサービスを作った。
何か思いつく毎にissueに書いて開発してて、手詰まりになったり精神が調子悪くなったら一旦手を止めて別のプロジェクトのissueを潰すようにしてると永遠にプログラマーズハイ状態を維持できるんだけど、自分の持っているissueを一覧できるページがGitHubにない。
GitHubには通知機能があるけど参加したりアサインされたissueしか通知されないので、全く手付かずのissueはだんだん下の方に下がっていって見つからなくなってしまう。
なので自分の持っているリポジトリ全体のissueを一覧したかった。
最近は21個のリポジトリをいじってて、73個もissue溜まってるんだなという事がわかる。
GitHub Issue Viewer
ソースコード
shokai/github-issue · GitHub
経緯
もともとこれgithubの自分のリポジトリのissue一覧
を使っていたんだけど動かなくなったのでカッとなって作った。でもさっきgithubのパスワードリセットしたら動くようになった。意味なかった。
意味ないけどスマホでも見れるからまあいいかも・・
実装
SinatraでGitHub OAuthする (2)にissue表示する機能を足しただけなので、だいたい2時間ぐらいでできた。issueの取得には時間がかかるから、1つリポジトリ取得する毎にsinatra-rocketioでブラウザに送っている。
取得したissueはmemcachedに3日間とっておいてる。
Arduinoを複数のRubyプロセスで共有したいの続き
Arduino Firmata on Ruby使うと複数のプログラムで同時に1台のArduino動かせるようになった。
v0.2.9をリリースした
gem install arduino_firmata
結局dRuby使う必要は無かった。
昔はserialport gemは1つのプロセスがportを専有してしまっていた気がするのだが、そうでもなくなってた。
Firmataの初期化プロセスを見なおしたら複数プロセスから使えるようになった。
サンプルの
arduino_firmata/samples at master · shokai/arduino_firmata · GitHub
– led_blink.rb
– on_analog_read.rb
– servo.rb
– digital_read.rb
を同時に動かせた。
1つのArduinoにあるセンサーを同時の複数のアプリから読み取ったりできるようになってコードがすっきりします。
1台で複数アプリ動かせて、アプリがそれぞれ別々にバージョン管理できるというのはものすごい利点です。よほど速度が重要な処理でない限りArduinoにコード直書きやめて、Ruby Firmata使いましょう。
1から254までpingうって反応あったホストにarpしてMacアドレスを取得した。
昔LAN内の全ホストにgrowl送りつけたりしていた時と同じノリだ
Raspberry PiがDHCPでどこに行ってしまったかもわかるし、定期的に実行すれば端末が(つまり人が)増えたり減ったりするのもわかって楽しい。
実行にはparallel gemが必要
gem install parallel
ruby macaddrs.rb 192.168.1.1