こつこつと

2008/09/17

iphoneでirc

iPhoneでIRCを使うべく、Webをさまよったけど、どうもIRCクライアントはよさそうなのがない。
というわけで、アプリはあきらめて、mobircのiPhone対応がされているみたいなので、
ブラウザ(Safari)経由で使うことにした。

インストールは以下に書くけど、基本はこのページでまとめられているので、そっち見た方がはやいかも。

もともと、tiarraは使っているので、そこは割愛。

基本的に、mobircがすでにiphone対応も取り込んでいるみたいなので、
CodeReposからsvnでさくっとダウンロード。
$ svn checkout http://svn.coderepos.org/share/lang/perl/mobirc/trunk/ mobirc


サンプルの設定ファイルをコピーする。
$ cp config.yaml.sample config.yaml

設定を適当にいじる。iphoneから使えればそれでいいので、以下みたいなシンプルなものに。
tiarraをjisで動かしていたので、incodeはjisにした。 utf-8にして、LimeChatもutf-8のほうがいいのかなぁ。
plugin:
- module: IRCCommand::TiarraLog
- module: Authorizer::Cookie
config:
password: xxxx
- module: Authorizer::BasicAuth
config:
username: xxxx
password: xxxx
- module: MessageBodyFilter::IRCColor
config:
# no_decorate: 0

- module: Component::IRCClient
config:
server: 127.0.0.1
port: 6660
nick: ku
desc: ku
username: ku
password: xxxxx
# incode: utf-8
incode: jis

- module: Component::HTTPD
config:
port: 6661


んで、
$ perl mobirc

と実行してみたが、モジュールがかなり足りないみたい。
参照ページのコメントの通り、
$ sudo -H sh -c "eval PERL_MM_USE_DEFAULT=1 cpan -H App::Mobirc"
で、CPANからmobircに必要なものをがっつり入れる。
PERL_MM_USE_DEFAULTは、設定しないほうが無難みたいですが、
入るモジュール量が半端なく、perlには無頓着な私はこのままいれちゃいました。

んで、
$ perl mobirc &

で、起動しました。

iphoneからも、ajaxで軽快にみれるようです。ただ、5秒に1回リロード?されるようで。
これ、電池すげーくいそうかも、と思いつつ、これでちょっとの間使ってみます。

私は、参照先のページと同様に、screenで動かしっぱなしですが、
ちゃんとdaemonっぽく動かすなら、daemontools(svtools)を使うといいかも。
たぶん、tiarraはrunっていうスクリプトがあるので、そのまま動くんじゃないかな(試してないけど)
$ supervise tiarra &

とか実行すれば、たぶん。
logとかちゃんととるなら、multilogとかも設定が必要?

mobircは、簡単なrunスクリプトが必要ですね。
単に、起動するだけで大丈夫じゃないかな。
#!/bin/sh
exec ./mobirc

とか。

2008/09/13

FlickrとPicasaへの画像アップロード

お仕事でいろんな写真サイトに手元の写真をアップロードするというのをやる予定です。
それに先駆けて、APIも整備されていて有名なところということで、FlickrとPicasaに挑戦してみた。

基本的に、作るのはDjangoのWebApplicationです。
WebApplicationの場合は、Flickr,Picasaとも、基本的に、ユーザからそれぞれのサイトの
ユーザ名とパスワードを預かるのは、さすがに、なんか気持ち悪いですよね、
というのに対処された認証になっているようです。
なんか世の中には、意外にその手のサンプルが少ないようなので、書いてみる。
まあ、ドキュメント読めば、普通に書いてるんだけど。

FlickrとPicasa(というか、Google)は、どちらもトークンというものを
ユーザ操作によって取得し、それを使ってユーザの画像を操作できます。
#Googleは、OAuthにも対応しているようですが、ライブラリが対応していないっぽいので、
#実績もあるしー、とかいう弱腰で、AuthSub方式を使いました。

とりあえず、どちらのサイトも、流れは以下になるようです。
・まず、各サイトへの認証URLを生成する
・そのURLへのリンクをクリックさせるか、リダイレクトする
・そのサイトで、このアプリから認証を要求されてるけど、承認するか?ページが表示される
・Cookieとかで認証済みなら、ボタン押すだけか、認証画面からログイン
 すると、自分のアプリサイト(事前に指定済み)のURLへリダイレクトされる
 そのとき、GETの引数として、トークンかそれに準ずるもの(flickrでは、frobというらしい)が渡される
・それを使って、永続的に利用できるトークンを取得する(昇格させる)
・それ以降は、それを使って、アップロード等の操作を行う

こっからは、実際のPythonででっちあげたサンプルコード(Djangoでサイト構築をした場合です。)
Flickrは、flickrpyを利用しました。
いまいち、これ以外に、トークンを使った認証にうまく対応しているライブラリを
見つけられませんでした。

とりあえず、FlickrでAPI Keyを取得します。
そのときに、認証後の戻り先のURL指定があるので、
http://xxx.xxx.xxx.xxx/flickr/gotFrob
というようなURLを指定しておきます。このURLでfrobを取得します。

とりあえず、viewだけ貼り付け。urlconfとかは適当に書く必要がもちろんあります。
あとは、Photoというモデルをつかってるけど、たいしたものでないので、省略。
とりあえず、やっつけこーど。さらに、!!!とか書いてるところはチョー適当。
ほんとは、生成したfrobをちゃんと覚えといて、ユーザとひも付けしないとだめだけど、
そこは適当に今は、渡されたfrobからtokenを取得して、ファイルに保存してるだけ。


from flickrapi import FlickrAPI

FLICKR_TOKEN = u'xxxx'
FLICKR_TOKEN_FILE_PATH = u'flickr_token.txt'
FLICKR_API_KEY = u'yyyy'
FLICKR_API_SECRET = u'zzzz'
FLICKR_PERMISSION = u'delete'

def get_flickr_api(token=None):
if token is None:
return FlickrAPI(FLICKR_API_KEY, FLICKR_API_SECRET, format='etree')
else:
return FlickrAPI(FLICKR_API_KEY, FLICKR_API_SECRET, token=token, format='etree')


def flickr_redirect_to_login(request):
flickr = get_flickr_api()
response = flickr.auth_getFrob()
frob = None
if response.attrib['stat'] == u'ok':
frob = response.findtext('frob')
else:
# !!!
return HttpResponse('Error')

return HttpResponseRedirect(flickr.auth_url(perms='delete', frob=frob))

def flickr_got_frob(request):
if request.method == 'GET':
frob = request.GET['frob']
flickr = get_flickr_api()
response = flickr.auth_getToken(frob=frob)
token = None
if response.attrib['stat'] == u'ok':
token = response.findtext('auth/token')
else:
# !!!
return HttpResponse('Error')

token_file = file(FLICKR_TOKEN_FILE_PATH, 'w')
token_file.write(token)
token_file.close()

return render_to_response('flickr/flickr_got_token.html',
dict(frob=frob, token=token))

def flickr_upload(request):
if request.method == 'GET':
photo_id = request.GET['photo_id']
photo = Photo.objects.all().filter(photo_id=photo_id).get()
token_file = file(FLICKR_TOKEN_FILE_PATH, 'r')
FLICKR_TOKEN = token_file.read()
token_file.close()
flickr = get_flickr_api(token=FLICKR_TOKEN)
response = flickr.upload(filename=photo.get_photo_url().encode('utf-8'), title=photo.caption)
flickr_photo_id = None
if response.attrib['stat'] == 'ok':
flickr_photo_id = response.findtext('photoid')
else:
# !!!
return HttpResponse('Error')

return render_to_response('flickr/flickr_upload.html',
dict(photo_id = photo_id, flickr_photo_id = flickr_photo_id))


流れは、
ユーザ操作によって、flickr_redirect_to_loginが呼び出されます。
すると、flickrの認証画面にとばされます。
んで、flickr_got_frobに帰ってきて、frobを使って、flickrからtokenを取得します。
んで、それを使って、flickr_uploadをつかって、アップロードする。

次は、Picasaの場合、同様にDjango前提。
gdata-python-clientで、AuthSubを利用します。
Picasaの場合は、事前にAPI等を取得するわけではなく、URL生成時に戻り先を指定する。
なんかアプリを事前に登録することで、
アプリ名とかがちゃんとGoogle側でも表示されるらしいので、やったほうがいいかも。
Picasaの場合は、frobのようなものはなく、1回限りのtokenという扱いで、それをsessionトークンに昇格させる。

ポイントは、これはバグだろーみたいな投稿もGoogle Codeであったけど、
Picasaの場合は、対アルバムにしかアップロードできないので、
InsertAlbumをとりあえずやってアルバムを作ってやろうとするけど、
こいつが対象のURLを生成する際に、self.emailを利用しようとする。
これは、ClientLogin()を使う場合は、email,passwordを指定しているから問題ないのだけど、
事前取得済みのsession tokenを使う場合、emailはわからない場合が普通。
そういうときは、Googleでは、'default'をURLとして指定すると、ユーザを勝手にGoogle側で決めてくれるようだ。
(これを調べるのに、ずいぶん手間取った。。。)
というわけで、本来なら、ライブラリ側のコード自体を、emailがNoneなら、defaultにするみたいするべきだけど、
ちょっとめんどくさかったので、emailに'default'をさくっと呼び出す前に代入した。
これで、とりあえず、うまくいくようにはなった。ただ、これはあまりにもやっつけすぎるかも。


import gdata.photos.service

PICASA_TOKEN = ''
PICASA_TOKEN_FILE_PATH = u'picasa_token.txt'

def picasa_redirect_to_login(request):
gd_client = gdata.photos.service.PhotosService()
auth_url = gd_client.GenerateAuthSubURL(next='http://xxx.xxx.xxx.xxx/picasa/got_token',
scope='http://picasaweb.google.com/data/',
secure=False, session=True)
return HttpResponseRedirect(auth_url)

def picasa_got_token(request):
if request.method == 'GET':
token = request.GET['token']
gd_client = gdata.photos.service.PhotosService()
gd_client.SetAuthSubToken(token)
gd_client.UpgradeToSessionToken()
token_file = file(PICASA_TOKEN_FILE_PATH, 'w')
token_file.write(gd_client.GetAuthSubToken())
token_file.close()
return HttpResponse('session token is %s' % (gd_client.GetAuthSubToken()))
else:
# !!!
return HttpResponse('Error')

def picasa_upload(request):
if request.method == 'GET':
photo_id = request.GET['photo_id']
import sys
photo = Photo.objects.all().filter(photo_id=photo_id).get()
gd_client = gdata.photos.service.PhotosService()
PICASA_TOKEN = file(PICASA_TOKEN_FILE_PATH, 'r').read()
gd_client.SetAuthSubToken(PICASA_TOKEN)
# bad techs
gd_client.email = 'default'
response = gd_client.InsertAlbum('test', 'test')
album_url = response.GetFeedLink().href
response = gd_client.InsertPhotoSimple(album_url, photo.caption, photo.comment, photo.get_photo_url())
return HttpResponse('picasa photo link is here' % response.GetSelfLink().href)
else:
# !!!
return HttpResponse('Error')


長くなったので、これでやめとこう。
とりあえず、こんな感じ。

iPhone 2.1

評判通り、いろいろよくなってますね。
・日本語入力は、確かにすげーサクサク!
・バックアップも確かにはやくなった
・電波状況の表示は、
 自宅は基本的に1本だったのが、基本5本に変化
 ソフトバンクさん、3Gエリアの改善要求とか送ってごめんw
 しかし、これ、電波の捕まえ具合がよくなったのか、
 表示がかわっただけなのか。

で、一つ解決されない疑問が、
・SMS 着信時の警告音繰り返し機能(2 回まで追加可能)
って、どこで設定するのだろう。。。
2chで何回か質問されてるみたいなんだけど、
見事なまでのスルーにちょっと笑った。
うちは、SMSでのやりとりが多いから、
この機能は是非使いたいんだけどなぁ。

【追記】
設定はなくて、SMSがきてるのに、なにも操作せずに放置すると、
5分後にもう一度、警告音が鳴るということだそうです。
なろほど。

2008/09/12

MacBookPro 再インストール

どうも動きがもっさりしてきていろいろ怪しい動きをするようになったので、再インストールした。

入れたもの
・ATOK 2008
 →とりあえず、これがないと始まらない。

・MobileMe
 →とりあえず、これでMail.appとかアドレスブックとかの内容を復元。
  メールアカウントとキーチェーンが復元されるのは、かなり楽でいい。
・Plaxo
 →主な目的は、iCal→GoogleCalendarの同期
  GoogleCalendarで最近対応した
  CalDavでがんばってみようと試みたけど、
  iPhoneと同期がOTAじゃ無理だった。
  ポイントは、
  PlaxoはGoogleCalendarの複数のカレンダーに対応できない。
  そのため、カレンダーごとに別のアカウントを作って、
  メインのアカウントに編集権限を与える形にする。
  Plaxoに同期エンドポイントを作るときには、
  作ったアカウントを登録しておく。
  これで、iCalをhubにして、
  iPhone,MobileMe,iCal,GoogleCalendarで予定の同期ができて便利。

・SSHまわりをレストア
 →鍵とかをなくすと、いろんなところに入れなくなる。
・MacFUSE,MacFusion
 →最近、開発はsshfs経由で編集しかしないので、ほぼ必須。
・DropBox
 →マシンが変わっても、ローカルにSyncしてくれる。
  いざというときには、Webから古い世代にもどしたり、
  削除したものを復活させられるのが便利。
  仕事用のドキュメントとかを入れている。

・Growl
 →特に、設定は変えないけど、
  IRCとかGmailとかのnotifyのために入れる。
・GmailStatus
 →未読チェック用。

・FireFox(lzycビルド)
 →FEBEでバックアップをとったつもりだったが、
  ProfileをRestoreしようとしたら、
  CPU 100%で暴走したまま固まる。。。
  泣く泣くextensionを手で入れ直した。
  ・Delicious Bookmarks これがないとなにもできない
  ・BetterGmail, BetterGCal
  ・FireBug 一応、Web屋さんなので
  ・GreaseMonkey 主に、LDRのため
   →UserScriptはもうなにを入れてたか覚えてないので、最低限入れた
    ・LDR Dedupe Entries
    ・LDR Full Feed
    ・Backx2 Livedoor Reader
    ・Shift+zっぽいことを自動的にしてくれるやつ

・SubEthaEdit
 →開発はこれで基本的にやってる
  特に、ここがイイ!っていうのはないけど、
  Pythonハイライトとかデフォルトで入ってるし。慣れ。
・ターミナル
 →元から入ってるやつ、これで結構いける。
  設定はProをベースにちょっと変えて使ってる。

・iCal
 →Plaxoから予定を復元。
  あとは、GoogleCalendarに社長とか会社の人の予定が入ってるので、
  それをCalDav経由で読み込む。
  GoogleAppsの別アカウントで認証が必要でも、
  CalDav経由ならちゃんと読めるのが便利。

・BathyScaphe
 →2ch.新・Mac,iPhone,AV機器あたりを板追加して終わり。
・夏ライオン
 →Twitterクライアントはシンプルなので、これをつかってる。
・iChat
 →Adiumとか使ってる人がおおいようだけど、
  必要なのが、MobileMeとGTalkなので、これで十分。
  インターフェースがかなり好き。
・Skype
 →打ち合わせ用。特に設定は変えない。
・LimeChat OSX
 →自宅サーバに、tiarraが入ってるので、最低限の設定をするだけ。
  基本的に、常に、ウインドウは出していないので、
  Growlで発言があったら、Notifyウインドウをだすようにしている。

・MPlayer OS Extended
 →とりあえず、ほとんどの動画が再生できるので、入れている。
・Flip4Mac
・Perian
 →まあ、念のため、という位の感じ。

・OnyX
・Secret
 →Finder、Dock,メニューバーあたりの設定を結構いじった。
  隠しファイル表示、
  ネットワークドライブでは、.DS_Storeつくらない、
  半透明なし、Dockに隙間つくる等

実は、再インストールが意外に大変ってことがわかった。
クラッシュ!とかなら、TimeMachineで復元ができるんだけど、
怪しいから再インストール→復元したら、
だめじゃん、みたいに気づいてちょっと鬱な感じ。
TimeCapsule未だ活用されず。。。

2008/09/08

iPhone買った

au W53CAからのMNP。スパボ一括。本体たけー。
絶対、2年とか使わないと確信してるので一括にした。

雑感。

i.softbank.jpの使いづらさに絶望。
MobileMeメインで使うのが、無難そう。
me.com→gmailの転送はやめずに、gmail側でフィルタ作って、
Inboxには入れずに、ラベルつけて、Archiveに直行させることにした。

とりあえず、メアド変更のお知らせメール送ったら、
i.softbank.jpも、me.comもPCメールと判定されるから、
結構、携帯以外のメール拒否ってる人から軒並み弾かれて帰ってきた。
me.comは仕方ないとしても、i.softbank.jpは一応、携帯の仲間に入れてくれないのか。

SMSがiChatっぽくて、慣れ親しんだ感じで楽しい。
これで、ほかのキャリアも使えればいいのに。

電話帳もMNPの場合は、自力で移行するしかない。
普通の携帯なら、赤外線で全件送信とかで、自力&無料で移行とか簡単にできる。
意外にこの方法使ってる人少ない気がする。
ソフトバンクショップのPCとかでがんばるよりは、楽だと思うんだけど。
とりあえず、ヨドバシ アキバのPCは軒並み故障とかで並んでる人がいっぱいいて、疑問に感じた。

結局、携帯から全部、携快電話使って、vCardで書き出して、Macでアドレスブックに読み込んだ。
よみがな入れないと、ソートがダメダメな感じなので、
手打ちでがんばった。30分くらいかかった。しんどかった。
これも、SoftBank内の機種変なら、なんか電話帳移行サポートみたいなページがあるんだけどねぇ。。。
そっちならうまくいくのかしら。

2008/09/06

MuninでTimeCapsuleのトラフィックを見る

TimeCapsuleは、SNMPに対応してるみたいなので、
我が家のルータとして、どれくらいがんばってるのかをグラフにしてみた。

使うのは、Munin
debianなので、
# aptitude install munin munin-node

これだけで、apacheがはいってたら、cronで5分ごとに、htmlが
/var/www/muninに生成されるようになるみたい。
使えるpluginとかは、munin-node-configureとか実行しなくても、
ローカルホスト分は、インストール時に設定してくれるらしい。

ただ、ホスト名が、localhost.localdomainで格好悪いので、
/etc/munin/munin-node.conf で

host_name xxx

を、適切に設定しておく。

んで、本題のTimeCapsule向けの設定追加。
ここで、ちょっと混乱したのは、Muninの動作の仕方。
ここまで、簡単に設定できすぎたので、よくわかってなかったのだけど、
Muninは、munin-nodeに接続して、各種情報を取得し、HTMLを生成するという形らしい。
つまり、SNMPを直接読むようなことにはならない。
ということで、SNMPから値を取得して、gateway的に動くmunin-nodeが必要ということらしい。
これがわかってなくて、munin.confのaddressの設定を直接TCのIPにして動かなくて、5分くらいはまった。

というわけで、気を取り直して。
まず、snmp周りのプラグインを有効にするためにも、
# munin-node-configure-snmp [TCのIPアドレス]
と実行すると、シンボリックリンクを張るためのコマンドが表示される。
注意は、実行されるわけじゃないこと。
# munin-node-configure-snmp [TCのIPアドレス] | sh
とかやるほうがいいかも。
うちの設定では、gec0, wlan0, vlan0のtraffic,errorsが追加された。
snmpwalkで見る限り、TimeCapsuleには、

1 gec0
2 mv0
3 pflog0
4 lo0
5 wlan0
6 vlan1
7 pppoe0
8 bridge0

という8つのIFがあるように見える。
なんで、上の3つだけ選ばれたのかは、謎。

うちのTimeCapsuleは、PPPoEでセッション張ってるので、
pppoe0
だけは、手動で追加した。
# ln -s /usr/share/munin/plugins/snmp__if_ /etc/munin/plugins/snmp_tc_if_7
# ln -s /usr/share/munin/plugins/snmp__if_ /etc/munin/plugins/snmp_tc_if_err_7
/etc/munin/pluginsのファイル名は、上のコマンドで実行されたものにあわせる。
最後の数字は、SNMPから取得できるintを使う。(上のリストアップの数字と一緒)

んで、/etc/munin/munin.confの設定。
以下を追加。munin-nodeが動いているホストのIPをaddressで設定。
バーチャルなノードなので、ノード名とホスト名はちがうので、use_node_nameはnoで。

[tc]
address 127.0.0.1
use_node_name no


とりあえず、これで、munin-nodeが動いているホスト以外にも,
tcというのができるはず。

gec0 -> 有線LAN(internal)
wlan0 -> 無線LAN
vlan1 -> 有線LAN(external)
pppoe0 -> PPPoE

かなぁ、とトラフィックを眺めて想像してみたけど、あってるかなぁ。。。
まあ、とりあえず、ウチのルータであるTimeCapsuleが
どれくらいトラフィック食っているかが、一目瞭然になって楽しい。
そして、Muninのほかのプラグインも試してみたくなるくらい簡単ですばらしいすな。

2008/09/02

debianにsshguard & 結果

自宅のサーバにも、sshguardを入れてみた。
こいつは、公開鍵での認証しか受け付けないのだけど、
まあ、一応、ということで入れてみた。

iptablesは周りは一緒。
syslogのままで最初設定しようとしたけど、どうもうまく動かず断念。

心機一転、syslogは実は重い、とか言われてる記憶とかもあって、
syslog-ngに変更してみた。
# aptitude install syslog-ng
で、さっくりとsyslogに変わってインストールされた。

んで、/etc/syslog-ng/syslog-ng.confの編集

filter sshlogs { facility(auth, authpriv); };
destination sshguardproc {
program("/usr/sbin/sshguard"
template("$DATE $FULLHOST $MESSAGE\n"));
};
log { source(s_all); filter(sshlogs); destination(sshguardproc); };


sourceが、サンプルでは、sourceという名前だけど、
debianでは、s_allとして定義されているので、そこだけ変更。

これで、動き始めた。

そして、結果。
1日に、3~4回、アタックを検知して、iptablesのルールを追加しているようだ。
大抵はうまく動いている。

しかし、本日のアタックは、なんとアクセスごとにsrcIPが違う。。。
いわゆる、botnetってやつですかね。
あきらかに、4アクセス/1secくらいの勢いで、違うユーザでログインを試みられているので、
連動しているとしか思えないのですが。。。
とりあえず、以下のようなコマンドで、IPを数える。
# grep ssh /var/log/messages | grep Invalid | gawk '{ print $10 }' | sort -u | wc -l

めっちゃ適当だけど、Invalid user guest from xxx.xxx.xxx.xxx
ていう感じの行を補足して数えてみると、350くらいのIPがある。

こういう場合は、現状、sshguardでは防ぎようがないっすねぇ。
単純に、IP縛りを外して、n秒間にm回以上ログインが失敗したら、で
ある程度の検知はできるかもしれんけど、そのあとのブロックのしようがないか。
全部、はじくわけにいかんもんねぇ。
過去に遡及して、失敗してるアドレス追加する?くらいかなぁ。
ちょっと改造してみようかな。。。