ぼくフルスタックエンジニア。

フルにスタックされすぎて積んでる人のブログ

【X-I】seccampに参加したい人のための、参加課題の解き方【IoTセキュリティトラック】

今回は、「seccampの参加課題の解き方」をテーマに、私がX-IトラックのIoTセキュリティトラック応募時に解いた課題の内容を解説していきます。他のトラックと違い、数学的な内容の一切ない取っ掛かりやすい問題だったので、みなさんもこれを読んでぜひセキュリティキャンプに応募していただけたら嬉しいです。

この記事について

この記事は、セキュリティキャンプ全国大会2020オンラインのグループワークメンバー「電源50Hz」が週替わりで作成するセキュリティ技術ブログとして作成しました。前回の記事は@shoumojiくんがまとめてくれた、プラットフォームセキュリティトラックの課題の解き方でした。

qiita.com

IoTセキュリティトラックとは

参加課題について書く前に、まずはトラックについて簡単に紹介します。

IoTセキュリティトラックとは、IoT機器を改造したり分解したりして脆弱性を探すトラックです。

f:id:gpioblink:20201121210017p:plain

公式のプログラム説明にはこのように書いてあります。

IoTセキュリティトラックでは、IoT機器が抱える脆弱性を明らかにするために、リバースエンジニアリングしたり、解析したりするトラックです。 このトラックでは、実際の機器がどのような仕組みで動作しているかを、分解したり様々な面から解析したりして明らかにしていくことで、IoT機器をセキュアにすることに貢献します。

昨年はチームで大型の機器を解析していたようですが、今年はオンラインになり各自が分解したい機器を解析しています。

まだまだ解析中ですが、UARTを探すところからSDR無線に触ったりなど様々な解析の技術に触れることができ、充実しています。

参加課題の解き方

では、さっそく本題の解説パートに入っていきます。

前回の@shoumojiくんのように、ほかのトラックでは高度な数学の問題を課せられたりしていましたが、私のトラックはそれとは全く違いました。

数学的な問題は一切なく、全て文章で記述する系の課題でした。

[問1] 今までにリバースエンジニアリング(分解や解析など)した経験を好きなだけ語って下さい。対象はソフトウェアやハードウェアに限定しません。

[問2] あなたが今一番リバースエンジニアリング(分解して仕組みが知りたい)したいものを紹介して下さい。

[問3] 以下の技術用語について解説してください。またどのようなところで使われているかも述べてください。わからない場合は調べて、自分なりに解釈した結果を述べてください。
「UART」「JTAG」「SPI(Serial Peripheral Interface)」「I2C(I-squared-C)」「ソフトウェア無線(SDR)」

[問4] 安全なファームウェアアップデートとは何ですか? もし、それができると攻撃者はどのような攻撃ができますか?事例などもご存知であれば合わせて紹介してください。

[問5] 分解や解析して、モノやソフトウェアの動く仕組みを知ることは楽しいと思いますか?また、それは何故かを好きなだけ語ってください。

[問6] 何か他にアピールしたいことがあれば、自由に書いてください。誤ったことを書いていても減点はしません。書いておきたいことはなんでも書いてください。

https://www.ipa.go.jp/files/000084572.txt

ここからは、一問一問について、どんな内容を記述したかや、どれだけの分量を書いたかまとめていきます。

[問1] 今までにリバースエンジニアリング(分解や解析など)した経験を好きなだけ語って下さい。対象はソフトウェアやハードウェアに限定しません。

この節では、今まで自分がやってきたリバースエンジニアリングだと思うことを4つほど書きました。分量はリンクを除き合計で1,300文字程度です。

正直、「動的に内容の変わるUSBメモリの作成」とかはあんまりリバースエンジニアリングではないし、「ゲームウオッチの修理」に関しては物理的な部品の交換といった話ですが、まあカスってはいるかなってという感じで書いてみました。

内容は、全て以前LT大会などで発表したことがある内容だったため、スライドを見て思い出しながらまとめてみました。この課題に限りませんが、LT大会とかに参加しておくと後で資料が残って便利です(笑)。

G-cluster

Linux搭載のクラウドゲーム機、G-clusterを改造して遊ぶためにリバースエンジニアリングをしています。 リバースエンジニアリングと言っても、「u-boot + Linux」の標準的な構成なので、GPLソースコードが公開されているので、基本的にはGPLのコードを見て、binary blobとなっているものをghidraにかけるて解析するといった感じです。

これまで、キーボード入力でシェルが表示できる改造、telnetや任意のコードを動かせるカスタムファームウェアの作成、本体を無改造でカスタムファームウェアに書き換える方法の確立など、様々なことを行なってきました。また、この改造手法は皆さんにもやっていただけるよう、GitHubでビルド用のdockerイメージを公開しています。詳しくは以下のスライドをご覧ください。

LTでの発表スライド: https://docs.google.com/presentation/d/1YEYMBgEgG0x2hvMznJAsaryp_-fJsX5qxnxtTTqJYlE/edit?usp=sharing

動的に内容の変わるUSBメモリの作成

DAMカラオケにあるUSB動画再生機能で、選曲した曲の動画を再生するため、動的に内容の変わるUSBメモリを作成しました。具体的は、DAM側でファイル名順での再生を開始して、USBメモリ側で選曲した曲に応じて再生したい曲をアクティブにするような処理を行なっています。

方法は、LinuxカーネルのUSBセルフホスト機能である、g_gadgetのg_mass_storageを使う方法と、WiFi内蔵SDカードを使う2つの方法を試しました。その結果、g_mass_storageはファイルの同時操作ができない仕様だったため、WiFi内蔵SDカードを採用して作成しました。

LTでの発表スライド: https://docs.google.com/presentation/d/1wdXzG0NPh0RGYVhOqvQTBSrI6N4m1_tIys7lo2ZzeI8/edit?usp=sharing

ゲームウオッチ・テレビの修理

最近はあまり行なっておらず、中学生や高校生時代の話ですが、趣味でちょっとした家電の修理を行なうことが出来ます。

例えばゲームウオッチでは、父と一緒にヤフオクでジャンク品を漁り、各種交換用部品を集め、2個1にしたり、偏光板と言われるパーツを取り替え表示をキレイにするなどをしていました。

また、マニュアル等がない状態で、テレビの裏蓋を開け、テスターで電圧を調べ電圧がおかしい3端子レギュレータを取り替え修理したこともあります。

[問2] あなたが今一番リバースエンジニアリング(分解して仕組みが知りたい)したいものを紹介して下さい。

これも問1と同様に正直に記入しました。以下に全文を張り付けています。

実際、今まで身の回りのおもちゃくらいしかリバースエンジニアリングしてこなかったので、どこかでもっと実用的な解析ができればなと思っています。

やりたいことは最新のハードウェアのハックです。これまでは壊れても良い安い基板や個人的に解析して使いたいものを解析していましたが、正直自分や周りの人を喜ばせるだけに留まっていました。もう少し予算をかけても今使われている話題のデバイスをハックしてより社会に貢献したいと思っています。

そのため個人的に今やりたいと思っているのは「電気自動車」のリバースエンジニアリングです。最近は電気自動車もIoTになり、オンラインで目的地をセットしたり情報を取得できます。またセンサー類での自動ブレーキや衝突回避の機能があります。そのため、個人的には最近の車はリバースエンジニアリングでハックされると命の危険もある危ない箱になっているのではないかと思っています。

[問3] 「UART」「JTAG」「SPI(Serial Peripheral Interface)」「I2C(I-squared-C)」「ソフトウェア無線(SDR)」について解説してください

いきなり問題らしい問題になりました!!(笑)。ちょっとした思考プロセス的なものを書いていきます。

Arduinoで謎のガラクタを作ったりする人ではあったので、解析的な意味での使い方は知りませんでしたが、Arduinoと外部モジュールを繋ぐための通信規格にも使われる「UART」「SPI(Serial Peripheral Interface)」「I2C(I-squared-C)」は元から知っていました。また、「UART」はG-clusterというLinux搭載ゲーム機をハックするのに触ったことがありました。

ちなみにその外部モジュールの1つにNFCタグリーダのPN532があります。これ1つで実は、「UART」「SPI(Serial Peripheral Interface)」「I2C(I-squared-C)」すべての通信規格に対応していたりしますw。

www.aitendo.com

逆に、JTAGとSDR無線については全く知らなかったので、調べながらまとめています。

回答の方針として、通信規格そのものの解説はせずに、これがどうリバースエンジニアリングなど解析と結びつくかを中心に記述するように気を付けました。ぱっと見Wikipediaでさっと調べてコピペできそうな問題ですが、通信規格そのものの解説ばかりで、セキュリティと結びつけるために、そこそこいろいろ調べる必要がありました。

実用的な意味での解説では、以下のサイトにあったPDF群がとても役立ちました。例えばUARTだったらRX、TXを基板上から見つけて解析するのですが、テスターで基板からそのピンを見つける方法まで書いてあり、謎が解けた気分になりました(笑)。

ruffnex.net

毎年使われている課題のようなので、自分の答えは省略しておきますが、文字数は5つの言葉の合計で約2,300文字になっていました。

[問4] 安全なファームウェアアップデートとは何ですか? もし、それができると攻撃者はどのような攻撃ができますか?事例などもご存知であれば合わせて紹介してください。

もっとちゃんとした答えがあるかもしれませんが、私は、マジコンとの戦いやゲーム機でのCFW実行を見てきた世代でもあるので、「他者によって改変されてないアップデート」なのかなと考えました。

そこから、マジコンやPARで出来た改造を思い出しながらまとめたり事例を書いたりして膨らませました。あんまよくないですが、以外と自分の過去の経験を書いていったら埋まってしまいました。。

この問題も毎年使われているようなので私の回答は省略しますが、最終的に約800文字になっていました。

脆弱性に関するおすすめの資料

ちなみに、Nintendo 3DSのハッキングシーンは、MITが講義ノートを公開していたりもするので、こういうノートを参考にするのもありだと思います。どうやって脆弱性を突かれたかがわかりやすく詳細にまとまっていてとてもおすすめです。

History of Hacking the Nintendo 3DS

[問5] 分解や解析して、モノやソフトウェアの動く仕組みを知ることは楽しいと思いますか?また、それは何故かを好きなだけ語ってください。

「楽しいと思いますか」という問は答えにくかったので、正直にこんな書き出しで書いていきました。

私は楽しいと思います。具体的になぜ楽しいと思うのかは主観となり説明するのは難しいので、なぜリバースエンジニアリングに興味を持ったかを含めて今までどのようなことをやってきたのか説明していきます。

ちょっとアレな話になってしまいますが、僕が初めて改造というものを知ったのは小学校の頃に遊んでいたポケットモンスターダイヤモンド・パールの「なぞのばしょ」でした。これはバグで簡単に通常捕まえられないポケモンを捕まえられる裏技でしたが、これに当時はとてもはまっていました。

このような改造にはまり始めた経験から、最近の低レイヤーのハックがをするようになったところまでを隠さずに正直に書きました。楽しさが伝わったかはわかりませんが、いろいろやってるなら好きなのかなとは思ってもらえたかなと思っています。

こんなこと言うのもあれですが、あまり深く考えず自分の思うように書ければいいんだろうなと思います。

最終的には、約1,200文字になっていました。

[問6] 何か他にアピールしたいことがあれば、自由に書いてください。誤ったことを書いていても減点はしません。書いておきたいことはなんでも書いてください。

「志望動機」と、あとは普段の開発などセキュリティ分野以外でやっていることを成果物のリンクなども貼りながらまとめました。

文字数には、リンクを除いて約1,800文字でした。

まとめ

今回は、セキュリティキャンプ応募編ということで、実際にどんな内容で応募したのかを解説しました。また後日、参加中の雰囲気ややったことなどについても書ければと思います。

グループワークメンバー「電源50Hz」では、他の人の応募体験記を公開していく予定ですので、ぜひそちらもご覧ください!

少しでも興味があれば、ぜひ応募してみてください! やはりオフライン開催も魅力的で、来年などオフラインで参加できる機会があれば僕もまた応募してみたいと思います。

【ハンズオン】動画から歩いている位置を把握!OpenVSLAMを使ってスマホのカメラで自己位置推定を試してみた

みなさん、カメラの映像から空間を把握して自己位置をマッピングしたいと思ったことはありませんか? 自己位置推定ツールのOpenVSLAMを使えば動画から自分のいる場所を自動でマッピングできます。 特殊な器具はなくてOK! なんの変哲もないスマホなどの普通のカメラでできるんです。

f:id:gpioblink:20201104174641g:plain

最終的にこのような画面でマッピングを確認することができます。この記事では、カメラの下準備からこの画面を表示するまでをハンズオン形式で書いていきます。

必要なもの

ツールのインストール

まずはOpenVSLAMの環境を作っていきましょう。まずはDockerで用意していきます。画面出力をX11上で行なうopenvslam-desktopとWebブラウザ上でopenvslam-socketの2つが提供されていますが、今回はX関連のエラーを避けるためにWebブラウザ上で動くopenvslam-socketを選択します。

公式のチュートリアルを参考にしながら、次のコマンドを実行していきます。

OpenVSLAMの入手

まずはOpenVSLAMのリポジトリを落とします。

git clone git@github.com:xdspacelab/openvslam.git
cd openvslam

この場所(openvslamディレクトリ内)のことを以下では「プロジェクトルート」と表現します。

OpenVSLAMのビルド

次にOpenVSLAM本体のopenvslam-socketとそれをWebから見るためのツールopenvslam-serverをビルドします。

docker build -t openvslam-desktop -f Dockerfile.desktop . --build-arg NUM_THREADS=4
cd viewer
docker build -t openvslam-server .

OpenVSLAMの動作確認

ここまでで下準備は完了です。次にOpenVSLAM側が公開しているサンプル動画で動作を確認してみましょう。

検証用ファイルをダウンロード

開発者のGoogleドライブからaist_entrance_hall_1.zipをダウンロードし、プロジェクトルートの下にmyexampleというディレクトリを作りそこに展開してください。

drive.google.com

ボキャブラリファイルorb_vocab.dbow2もダウンロードし、同様に展開してください。

drive.google.com

OpenVSLAMの起動

2つのターミナルを開き、プロジェクトルートに移動してから次の2つのコンテナを起動します。 macOSの方は手順が異なるようなので公式ドキュメントを参照してください

Webサイト表示用

docker run --rm -it --name openvslam-server --net=host openvslam-server

OpenVSLAM処理用

vオプションでmyexample内のファイルをDocker内と同期させています。

docker run --rm -it --name openvslam-socket -v "myexample:/openvslam/myexample" --net=host openvslam-socket

テスト

まず、ブラウザから http://localhost:3001 を開きます。

次に「OpenVSLAM処理用」のコンソールで以下のコマンドを実行します。

./run_video_slam \
    -v ../myexample/orb_vocab/orb_vocab.dbow2 \
    -c ../myexample/aist_entrance_hall_1/config.yaml \
    -m ../myexample/aist_entrance_hall_1/video.mp4 \
    --frame-skip 3 \
    --map-db aist_living_lab_1_map.msg

この操作をして、ブラウザ上の画面にマッピングが表示されたらテストは成功です。 立てた2つのコンテナは終了してください。

f:id:gpioblink:20201105105415p:plain

カメラの準備

早速、手持ちのカメラで撮った動画で試したいですが、その前にカメラの固有値を設定する「キャリブレーション」という処理でカメラの内部パラメータを特定し設定する必要があります。

カメラの内部パラメータとは

内部パラメータとは、画素の大きさやカメラの中央からのズレ幅のことです。2次元の画像から3次元の位置を求める(3次元復元する)ためには、カメラの内部パラメータを知っておく必要があります。これをカメラ毎に正しく設定しないと、正しくマッピングできません。

いろいろ難しい計算が必要ですが、チェッカーボードを使えばOpenCVで自動計算できます。

ここでは、以下のサイトの内容に従ってチェッカーボードでキャリブレーションを行なっていきます。

labs.eecs.tottori-u.ac.jp

チェッカーボードの用意

このサイト中段にあるcheckerboard.pdf(13x9)を印刷して使いました。

A4の紙に印刷して、硬いものの上にピッタリ貼り付けてください。

w.atwiki.jp

キャリブレーション用写真の撮影

キャリブレーションでは最終的に画像を用いますが、写真モードと動画モードではカメラの内部パラメータが変化する可能性があるので、まずは動画を撮影しコマをキャプチャして使うのがおすすめです。

カメラを三脚やスマホスタンドなどで固定して、様々な角度から格子を撮影してください。

私は、撮影した動画ファイルをPCに転送した後、VLCスクリーンショット機能で20枚程度の写真を抽出しました。

f:id:gpioblink:20201105111737p:plain

OpenCVによるキャリブレーション

このサイトのチュートリアルに従って、写真を入れたディレクトリ上で以下のコードを実行しました。

import numpy as np
import cv2
import glob

# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((13*9,3), np.float32)
objp[:,:2] = np.mgrid[0:13,0:9].T.reshape(-1,2)

# Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.

images = glob.glob('*.jpg')

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

    # Find the chess board corners
    ret, corners = cv2.findChessboardCorners(gray, (13,9),None)

    # If found, add object points, image points (after refining them)
    if ret == True:
        objpoints.append(objp)

        corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
        imgpoints.append(corners2)

        # Draw and display the corners
        img = cv2.drawChessboardCorners(img, (7,6), corners2,ret)
        cv2.imshow('img',img)
        cv2.waitKey(500)

ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)
print("ret", ret)
print("mtx", mtx)
print("dist", dist)
print("rvecs", rvecs)
print("tvecs", tvecs)

fs = cv2.FileStorage('calibration_result.yaml', cv2.FILE_STORAGE_WRITE)
fs.write('intrinsic', mtx)
fs.write('distortion', dist)
fs.release()

cv2.destroyAllWindows()

実行中にはウィンドウが開き以下の様な画像がバンバン表示されて、最終的なキャリブレーションの結果がターミナル上に表示されます。

f:id:gpioblink:20201105112755p:plain

以下のようなcalibration_result.yamlが出ればキャリブレーション用の値取得は完了です。

%YAML:1.0
---
intrinsic: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [ 1.8921551800170096e+03, 0., 9.4035838675468960e+02, 0.,
       1.8900754975516727e+03, 5.3822505221063818e+02, 0., 0., 1. ]
distortion: !!opencv-matrix
   rows: 1
   cols: 5
   dt: d
   data: [ 2.9967145140423967e-01, -1.5951350392495047e+00,
       -2.4978008305846832e-04, -5.0818139267033513e-03,
       2.8435830856943536e+00 ]

OpenVSLAM用の設定ファイルを作成

このキャリブレーションした値をOpenVSLAM上に読み込ませるにはOpenVSLAM専用のフォーマットにする必要があります。

最終的には以下のようなconfig.yamlファイルを作ります。先程のOpenCVの実行結果でカメラ行列で出力されたデータを、OpenVSLAM用に必要な要素だけ抜き出して指定します。

#==============#
# Camera Model #
#==============#

Camera.name: "Pixel3 (Sony Exmor for mobile IMX363)"
Camera.setup: "monocular"
Camera.model: "perspective"

Camera.fx: 1892.1551800170096
Camera.fy: 1890.0754975516727
Camera.cx: 940.35838675468960
Camera.cy: 538.22505221063818

Camera.k1: 0.29967145140423967
Camera.k2: -1.5951350392495047 
Camera.p1: -0.00024978008305846832
Camera.p2: -0.0050818139267033513
Camera.k3: 2.8435830856943536

Camera.fps: 30.0
Camera.cols: 1920
Camera.rows: 1080

Camera.color_order: "RGB"

#================#
# ORB Parameters #
#================#

Feature.max_num_keypoints: 2000
Feature.scale_factor: 1.2
Feature.num_levels: 8
Feature.ini_fast_threshold: 20
Feature.min_fast_threshold: 7
Feature.mask_rectangles:
  - [0.0, 1.0, 0.0, 0.1]
  - [0.0, 1.0, 0.84, 1.0]

fx、fy、cx、cyの部分には、calibration_result.yamlのintrinsicのカメラ行列の該当する場所の値にします。

 \begin{bmatrix}f_x & 0 & c_x \\0 & f_y & c_y \\0 & 0 & 1 \end{bmatrix}

k1、k2、p1、p2、k3はcalibration_result.yamldistortionの順番でそのまま差し込みます。

他は必要に応じて名前やフレーム数、解像度の設定を行なってください。

設定が完了したら、<プロジェクトルート>/myexample/my_video_slam/config.yamlに保存してください。

カメラでの自己位置推定

それでは、ここまでで用意が整ったので、早速マッピングを行なってみましょう!

まずは適当な建物の中を歩いた動画を撮影してきてください。

その動画を<プロジェクトルート>/myexample/my_video_slam/video.mp4に置いてください。

あとはテストの時と同様にopenvslam-socketopenvslam-serverのコンテナを起動して、次のコマンドを実行すると。。。

./run_video_slam \
    -v ../myexample/orb_vocab/orb_vocab.dbow2 \
    -c ../myexample/my_video_slam/config.yaml \
    -m ../myexample/my_video_slam/video.mp4 \
    --frame-skip 3 \
    --map-db my_video_slam_map.msg

記事冒頭のgifのような任意の動画でのマッピングに成功しました!

f:id:gpioblink:20201104174641g:plain

まとめ

今回は、私が奥山先生とやっている研究からOpenVSLAMの使い方について紹介しました。

次回は、地図作成の方を書いていきたいと思います。

特殊な機材が何もいらない、夢が広がる楽しい技術なので、みなさんもぜひ活用してみてください!

基板作成について調べてArduino名刺基板を設計してみる (準備編)

今回は、Eagleをちょっと触ったことある程度の初心者が、Arduino内蔵名刺基板設計をする話をしていきます。おそらく3回くらい分かれる記事のうち、最初の1回です。この記事では、どんな回路や仕様にするか考える話を中心に書いていきます。

名刺基板とは?

その名の通り、基板の形をした名刺です。「名刺基板」で画像検索すると、国内外問わず様々な作品があるようです。

ものによっては、実際に回路として動作する基板を作られている方もおり、

USBメモリにしたり

gigazine.net

Linuxを内蔵したり

gigazine.net

シンセサイザーにしてしまった作例もあるようです

hackaday.com

で、今回、いろいろあって学内で名刺基板作成講座をすることになったので、このシリーズではその準備ログをまとめていきます。なるべく読まれた方が記事を追って実装できるように書いていくつもりですので、よろしくお願いします!

何を作るのか

こんな感じの要件で考えてみました

  • 受講者が気軽にプログラムを書き換えて楽しめるもの
  • なるべく部品点数は少なく、名刺なのでなるべく基板の背は低く
  • オンライン講座を考慮して、ISP等の書き込み装置等、別の機材が必要になることはしない

「受講者が気軽にプログラムを書き換えて楽しめるもの」から、Arduino互換にすることはすぐ思いつきました。

また、「ISP等の書き込み装置が必要になることはしない」という条件から、atmega328pのarduinoは使えなそうです(Unoみたいにatmega16u2も付ける形もできなくはないけど、パーツ数が多くなるのはイヤ)。

そこで、調べているうちに、「U」付きモデルのArduinoならハードウェアレベルでのUSB対応かつ新品の状態でUSBからファームウェアを書き込める、DFU(Device Firmware Update)が付いていることが分かりました。そこで、Arduinoで採用実績のあるatmega32u4を使用することにしました。

オリジナルArduino基板設計の準備

atmega32u4といえば、「Arduino Micro」と「Arduino Leonardo」があります。そして、もちろんオープンソースハードウェアなので回路図は公開されています。

eagleのschematicやboardのデータもあるので、改変も楽です。

store.arduino.cc

store.arduino.cc

ここからminumumな構成にするためいらないパーツをバッサリ切り取り、作っていこうと思います。

。。と思ったのですが、実は調べているうちに、Arduino Leonardoの極小ボードである、Beetleを発見しました。

www.dfrobot.com

これのschematicも公開されていたので、これをベースにUSBを基板上に配置したり気の利いたLEDを追加するなどして、名刺基板に近づけていこうと思います。

オンボードUSB-A端子の設計

ここで特殊な部品として、オンボードのUSB-A端子が有ります。ライブラリ等も特に見つからなかったので、手作りすることにしました。

ここに先人のUSB名刺基板ログがありますが、ここでのUSB-A端子は実測のようです。

www.instructables.com

ネットに転がっていたUSB2.0の規格書を漁ると、こんな形で詳細な寸法が載っていました。

http://sdphca.ucsd.edu/lab_equip_manuals/usb_20.pdf

f:id:gpioblink:20200804220707p:plain

f:id:gpioblink:20200804220805p:plain

これだけあれば、独自のライブラリを作れそうです。

次回の記事で、実際に実装を行います。

おまけ

今回は採用しませんでしたが、Arduinoの基板をブロックに分けてとても分かりやすくまとめてくれています。 元になった基板は古いようですが、どこまでがリセットに関する回路なの?みたいな疑問に答えてくれ、とても役に立ちました。

Arduino-modular

また、極小のLeonardo基板をあげられている方も、仕様決定の上でとても便利でした。

forum.arduino.cc

https://forum.arduino.cc/index.php?action=dlattach;topic=111503.0;attach=20930

Arduino基板設計に関する記事を見ていると、「Arduinoのフォーラムで聞いて解決した」とか「stack exchangeで聞いて理解した」みたいな情報を結構見ました。周りに聞ける人がほとんどいない分野なので、ためらいなく活用していこうと思います。

進捗出し研究のための評価

この記事は、「進捗出し研究ブログ」の1日目記事です。

gpioblink.hatenablog.com

この記事の最後に、このブログ記事でやった内容に関する進捗評価をしておきます。

  • 「基板作成講座の準備」について「研究室」でやった
  • 目標の作業は終了しなかったが作業中に何かの誘惑に負けることはなかった
  • 途中疲れたときに15分の休憩を2回、45分の休憩を1回とった
  • 目標時間の6時間が過ぎた後も続けて最終的に寝落ちした

進捗度: ★★★★☆

少し休憩の割合が長い気もするが、概ね集中できていたように感じる

【どこでやるのが進捗でるのか】毎日更新!進捗出し研究ブログやります

こんにちは!じぶりんです。 今回は、今月の間、毎日ブログを更新して書くつもりの「進捗出し研究ブログ」について動機やルールについて書いていきます。

動機

最近、時間に対して進捗がうまく出せてないと思う日々が続くようになりました。

いろんな要因があるとは思いますが、気分のようなもので評価するのは難しいので まずは測りやすい指標である「場所」を変えて試してみたいと思っています。

そこで、今月は場所をメインの軸にしてテーマを変えつつ進捗が出たかの成果を評価を書いて生活していきます!

実施方法

  • 「学習場所」と「取り組んだテーマ」ごとに評価
  • 1回の取り組む時間は6時間
  • 1つの「学習場所」につき各4回やる
  • 取り組んだ内容を毎日ブログに書く

学習場所一覧

  • カラオケ / ネカフェ [2回ずつ]
  • 大学内の24H自習室
  • 自宅
  • 研究室
  • 学内(演習室等、その他の学内)
  • Discordのオンライン自習室
  • YouTubeでの進捗配信

テーマ一覧

  • 基板作成講座の準備(Arduino名刺基板作成後、Linux名刺基板について研究)
  • カラオケハッキング(歌詞改造GUIアプリの作成)
  • G-clusterライフハック(最強カスタムファームウェアの作成)
  • WiFiを使った位置検出システムの作成(複数のG-clusterのAPで強度判定)
  • アニメタイピングの完成(未踏で作ったものの完成)
  • LTスライド作成
  • バイトのタスク
  • 課題・宿題

予定

基本的に、進捗や期限によるのであまりガチガチに予定を立てるつもりはありません。その日にやったことの結果を書いていくつもりです。

あと、この話とは直接関係ありませんが、夏のインターンは「リクルート」と「GMOペパボ」に行けることになりました。期間はどちらも9月ですが進展があればこちらも報告していく予定です。

それでは、早速、今日の夜から更新していきますので、よろしくお願いします!

クリーンアーキテクチャ本を読んだ感想

「クリーンアーキテクチャ 達人に学ぶソフトウェアの構造と設計」を読んだのでその感想と次やることを書いていきます。(感想というより読書メモだなこれ)

動機

最近、設計をちゃんとしたアプリを開発したいと思い、いくつかクリーンアーキテクチャをベースとしてコードを書いているつもりです。まずはコードを写経して、クリーンアーキテクチャがどんなものか知りました。カラオケのバイナリ解析アプリを作るなどして実際の個人開発で使ってみました。また、今やっているGo言語のプロジェクトでは、クリーンアーキテクチャをベースにボイラープレートを作ることでチームで担当分けした開発がしやすくなりました。

github.com

しかし、書いているうちにしばしば、本当にクリーンアーキテクチャとして正しいのか不安になることがありました。例えばGo言語のプロジェクトでは、まだ開発中ですが、つなぐ部分のコードばかり大きくなり実際の実装は数行になっていたりします。カラオケのものでも、結局カラオケの歌詞バイナリデータから汎用的なデータに変換するために、コアのロジック(ドメイン)でバイナリを扱っていたりして、本当にいいのかと不安を持つこともありました。

この点を踏まえ、今回はこのクリーンアーキテクチャの本、特に後半のアーキテクチャの話について詳しく読んでいきました。

メモ

コンポーネントの依存グラフにおける循環依存があるとコンポーネントが密結合して面倒になる

正直、これまでの設計でやってしまっていると思いました。これはクリーンアーキテクチャの丸い円だけを見ていても気づけない問題です。

この図でEntitiesからAuthorizerに伸びている依存は、これのせいでAuthorizerとInteractorsとEntitiesが有効エッジで循環させている。これがあると、DatabaseがこれまでEntitiesとの依存性だけを考えていたのに、Authorizerへの依存性や、それ経由でのInteractorsまでへの依存性まで考えないといけなくなるらしい。

これはただ、DIPで依存性を逆転するだけで解決する問題ですが、インターフェイスをバンバン作っていたらそれはそれで循環依存になってしまいそうで怖いです。クリーンアーキテクチャを書き始めてから全部継承にして、極力依存させないぞなんてやっていたのでコンポーネント図も書いて意識したほうがよさそうです。

f:id:gpioblink:20200417213029p:plain

プロジェクトの開始時にコンポーネント図を作ることはない(できない)

私は、今まで設計は最初にやってそれをもとに組み立てて行くのを続けていました。何か新しいものを開発することになれば、とりあえず紙を持ってきてマルをグルグル書いて、クリーンアーキテクチャを組み立てていました。あとはこれを元に円の真ん中から書いていくようなことをしていました。

さっきの密結合の話でよし、じゃあ最初の設計段階でグルグルの他に書いてみるかと思った矢先、それは無理らしいです。MainとかViewとかPresenterが並んでいる典型的な図を見る限り初期でもある程度はできそうだと思っていたのですが、これは作ってみてから依存性を把握するための地図という位置づけのようです。

f:id:gpioblink:20200304115159p:plain

この本では、コンポーネント図はアプリケーションの機能について書くわけではなく、ビルド可能性や保守性を見るための地図だと書いてあります。とにかく、相互の関係をどう落としていくかの話はレイヤーが違うと気付かされました。

安定度・抽象度等価の原則(SAP)と安定依存の原則(SDP)の組み合わせが、コンポーネント版の依存関係逆転の原則(DIP)に相当する

あまり意識していませんでしたが、クリーンアーキテクチャは型のない言語にも使えるようです。

抽象度は「I = コンポーネント内の抽象クラスとインターフェイスの総数 ÷ コンポーネント内のクラスの総数」、 安定度は「ファン・アウト(依存入力数) ÷ (ファン・イン(依存出力数) + ファン・アウト)」で出すらしいことを知りました。 そして抽象度が高くなる方向へ依存するようです。

本でも「コンポーネントの安定度や抽象度はきちんと区別できるものではない」と言っている通り、正直これを知ってしても型なしの言語で上手く活用出来る気はしませんが、近いうちにPythonでなんか書いて使ってみたいと思います。苦痛ゾーンとか無駄ゾーンに分けてコードをちょっとだけ数学的に評価するのとかやってみたい。

ユースケースとはこんなもの

こういうのって様々な意見があるんだろうけど、これは実際のコードを見る中でもかなり上手く言語化されているように感じてとても好きです! 人によってはユースケースに「〇〇というボタンを押したら〇〇が起きて…」のような詳細が書かれていることがありますが、なんか粒度が細かすぎる気がして本当にそれでいいのかと疑問になることがしばしばあります。

これはユースケースなので、ここから呼ばれるものはビジネスロジックです。つまり円の中央ドメインに何を置くべきか書いてあるとも言え、この例はとても貴重な気がしています。

f:id:gpioblink:20200416164354p:plain

アーキテクトの目的は、方針とは無関係に詳細を決めながら、方針をシステムの最も重要な要素と認識するシステムの形状を作ること

あまり長期的な目線で設計していなかったので、この考え方は斬新でした。確かに、開発初期でWebサーバで配信するかREST使うかは決める必要はありません。 詳細の決定を延期や保留することができるのは、確かに仕様が確定していない開発段階などから使えて重要そうです。

組み込みクリーンアーキテクチャでは、OS抽象化レイヤー(OASL)やハードウェア抽象化レイヤー(HAL)を使って詳細をユーザーに明らかにしなくする

ロボットサークルとかでmbedのコードを書いたりしますが、どうしてもESP(WiFi)を使うとき送信時のウェイトなどでハード依存になっている所がありそうです。ある程度は関数などを活用して分けられていると思いますが、抽象化レイヤーという意識をすればもっと分離できそうです。同じ意味で、条件付きコンパイルとか多用するのも「Don't Repeat Yourself原則」違反にもなり好ましくないらしい。

新機能をポリモーフィックに扱うようにしないと、機能追加などで全てのサービスを変更するハメになる

新機能の追加をオープン・クローズドの原則にしたがってできるようにするには、ロジックを依存性の関係に従って抽出できるようにする必要があるようです。 この辺りは経験を積まないとどんな感じで分けられるか分からないような気もしますが、将来の変更も意識できるようになると強そうです。

f:id:gpioblink:20200417221612p:plain

感想

今回、この本を読むことで「なんとなくクリーンアーキテクチャっぽく円を書いて設計していた」部分で、依存性循環とか具体性があいまいなユースケースなど実はヤバそうだと思う例を見つけることが出来ました。元から、コンポーネントでやる部分を明確にできるので、あまりコミュニケーションが取れない環境でチーム開発する際とかにも重宝しそうな設計だと思っていました。この結果を元にさらにいくつかアプリを作って、とりあえず個人レベルでまずはより変更しやすいクリーンアーキテクチャを目指して設計してみようと思います。

次やること

この本を読んでも、やはりアイディアからコンポーネントに落とすまでのフローが部分的には情報があるものの具体的に書いてあるわけではなく、もう少し設計を学んでいきたいと思っています。今後は、とりあえず聞いたことのあるDDDやTDDといった手法について詳しく学んで、設計についての知識を深めていきたいと思っています。

reactでタイピングアプリのプロトタイプを作ってみた / 「2020年度未踏IT人材発掘・育成事業」に応募しました

今回は、未踏事業に応募したことの報告と、その時に作成したプロトタイプの技術的な解説を書いていこうと思います。

未踏事業とは、簡単に言えば「今まで見たことも聞いたこともない面白いプロジェクトを応援するよ〜」ってやつで、デザイニウムで誘われて知りました。最初聞いたときは水戸納豆と聞こえて、工場見学か何かだと思っていましたw

応募した企画

f:id:gpioblink:20200310145424p:plain
プロトタイプへのリンク

今回作る予定のものは、「誤答理由判定機能付きディクテーションプラットフォームの作成」で、英語学習に動画とタイピングを足した、新しい英語学習メソッドです。

まずは、ぜひプロトタイプを触ってみてください。動画を再生して、聞き取った内容をぜひ入力してみてください。未実装ですが、本来なら右枠にダミーテキストではなく、間違えた部分の解説が表示されます。

正直、あまり未踏を感じないというか、既存のものを組み合わせただけではないかと思うかもしれません。実際、タイピング部分ならDicaptionTypingTubeが、復習ゲームなら懐かしの特打にだってあります。もちろん私自身、このプラットフォーム全体で見ると、ほとんどの機能は常にどこかにあると思っています。

そこで、今回作るものには次の4つのユニークな特徴があることを強調しておきます。

  • 様々な動画サイトのコンテンツを使える
  • キーボードの入力から誤答理由を判定して活用できる
  • 実際の文法書と構文解析を組み合わせて適切な解説を表示できる
  • タイピングだけで終わらず様々なアプリや機能と連携する

つまり、「キーボードで好きな動画を見ながら文を入力しているだけで自分の語学レベルに応じた今知るべき解説やフォローが得られる」ということです。全く同じ動画で遊んでいても、利用者の傾向に合わせて解説や学習方法が自動的にレコメンドされるのです。これまで、フロントやバックエンドを書くことはあっても、人工知能などをゼロから実装することはありませんでした。未踏を1つの機会として、自分の弱い部分を埋めていこうと思います。(注: 応募段階です)

ここではプロトタイプの技術的な解説もしたいので、詳細な説明は省きます!興味を持たれた方はぜひ全文をご覧ください。

docs.google.com

プロトタイプについて

ここからはプロトタイプの中身について詳しく説明していきます。

まず、今までVueしかやっていなかったため、そろそろ別の言語をと思いReactに挑戦してみました。ちなみに、VueといってもいつもデザインフレームワークのVuetifyとBackend-as-a-ServiceのFirebaseで手抜きばっかりしていました。今回は、キーボードの入力コンポーネントや動画取得のためのバックエンドなどが必要だったためこのような手抜きはせず1つ1つ作っています。

Reactやコンポーネント作成経験ゼロの人がどこにつまづくか知る記事としてもご利用ください(苦笑)

事前学習・環境構築

まず、ReactもStorybookも利用経験がなかったため、Reactは公式の日本語ドキュメントを一通り読み、Storybookは公式のチュートリアルを終しました。 www.learnstorybook.com

また、新しい言語や手法でコードを書くときはリファレンスにするリポジトリを作って、分からなくなったときはそれの通りに実装するようにしています。今回はこのリポジトリに、「create-react-app-typescript-todo-example-2019」を選んでみました。定番のTODOながらHooksはもちろんテストやデザインに関するツールが多数含まれていて、参照するのにとても役立ちました。

github.com

というわけで、ボイラープレートには、create-react-appを使用しました。 create-react-app.dev

コンポーネント作成にはstorybookを使用しましたが、typescriptのテンプレートを使用している場合でも公式サイトにあるやり方では、jsで入ってしまうようでした。いろいろググりまくった結果、この記事の通りやると上手くtsで導入できました。

npx -p @storybook/cli sb init --story-format=csf-ts

Storybook Docs Typescript Walkthrough · GitHub

設計

普通はFigmaのようなプロトタイプツールを使うのでしょうが、やっぱり紙に書いたほうが早いので最近は紙で設計するようにしています。

データをどこで持つかなども含め、画面のレイアウト等を設計しました。

f:id:gpioblink:20200314113701p:plain

タイピングコンポーネント作成

準備ができたので、早速キーボード入力部分のコンポーネントを作成してみます。 CSSのGridを使って、フォントによらず文字を等間隔に並べたりタグバーの表示が簡単に範囲指定出来るように工夫しました。

f:id:gpioblink:20200314105641p:plain

ここでちょっと悩んだのは、キーボードの入力をどこで受け付けるかです。

このアプリでは文字の1つ1つが独立してコンポーネントになっており、それぞれが「入力前」「入力中」「入力完了」といった状態を持つようになっています。 最初は、この独立した文字1つ1つにキーボード入力をもたせるようにしていましたが、同時に入力中になってよいのは入力完了した文字の次の文字1つのみのため、この方法では管理が大変でした。

そのため、タイピングコンポーネント全体でキーボードからの入力イベントを受け取り、それをPropsのバケツリレーで回す形を取りました。

動画再生コンポーネントの作成

今回は、YouTubeに縛らず世界の様々な動画サイトに対応させたかったため、YouTubeの埋め込みプレーヤーはあえて使用せずに、video.jsを使って実装しました。

そのため、YouTubeの埋め込みのリンクではなく、「.m3u8」や「.mp4」といった動画そのもののソースURLが必要になりました。これはPythonの超有名リポジトリyoutube-dlで取得できるので、このソースURLを取得するためのバックエンドをサーバーレスで作成しました。

f:id:gpioblink:20200314112108p:plain

一度にリクエストがあると、「429 Too Many Requests」になって上手くいかないため、キャッシュするなどして対応しています。

このサンプルではYouTubeから動画を取得していますが、この実装方法によりイギリスBBCやオーストラリアSBSなどテレビ局のオンデマンドサービスや、PokemonTVなどのマイナーな配信サービスのサイトURLを使っても動画が取得できるようになっています。

ソースコード

github.com

今回作成したプロトタイプのソースコードはこちらで公開しています。 (バックエンド部分は、video-typing/misc/serverless-video-source-finder/video-typing-backend/に入っています)

今後

今回、設計の面では紙に書いたとは言え、データの持つ場所などかなり適当になってしまいました。 表示だけのコンポーネントがあると思えば、キーボード受付しているものもありあまり良くないと思っています。

結局Fluxも使わずにPropのバケツリレーなどを行なっていたので、また何か開発しつつ改善していこうと思います。(調べてみると、必ずしも悪ではないと書いてありますが、経験が少ないためまだまだよく分かっていません。。)

いま、そんなことを考えながらもう一つReactでアプリを作っているので、完成次第報告していきます。

Stripeを知らない状態から使って20時間で中古本販売プラットフォームを作ってみた / JP_Stripes in Aizuに参加してきました

この前、会津若松市内で行なわれたJP_Stripesに参加してきました。 今回はその感想と、そこで私が行なったLT「20時間で作る中古本プラットフォーム」の内容を書いていきます。

eventregist.com

「MaaSアプリのその後、無人コンビニアプリとかマッチングアプリとか試飲サブすくとか」(デザイニウム前田さん)

普段、決済サービスを利用客の立場からしか見ない私ですが、企業の目線からの話を聞くことができました。

店舗側としては、電子決済の入金日が翌日入金か月末振込かで導入しやすさが変わるそうです。さらに、決済された金額は、全額会社持ちではなく、関係者に分配しなくてはいけません。分配のしやすさなども決済サービスの決め手になるそうです。

割引に釣られて、いろいろな決済サービスを多様している僕ですが、企業側のことも考えないといけないんだと分からされました。やっぱりエンジニアだからって、ソフトウェア関連の技術しか手を出さないと置いていかれそうだなと感じました。

最近、「会津大学教養学部」なんてイベントを開いて、心理学に手を出したりしていますが、間違ってないななんて思いました(笑)

「システムの一貫性に寄与する設計」(@acomagu)

いつも分かりやすくためになる説明をしてくれるacomaguさんが、今回は一貫性のある設計について詳しく話してくれました。今回は、いろんな層の人が来ることを意識してか、とても分かりやすい説明をしていただきました。

内容は、ほとんど忘れてしまいましたが、「イベントソーシング」の話がとても心に残っています。

確か、次のような話でした。

ウェブサイトのカウンターを考えてみましょう。直感的な手法では、アクセス毎にサーバー側上の変数に1を足すようにするでしょう。しかし、これでは同時にアクセスがあった場合、正しく記録できない可能性があります。そこで、イベントソーシングを使います。イベントソーシングでは、値を直接変えるのではなく、「何時にアクセスがあった」ことをデーターベースにログのように追記で記録します。これによって、同時に書き込みがあっても、データーベースから行数を数えることで正しいカウンター表示ができます。

最近、「とりあえず動くものを作るだけの人」から脱却しようと設計を意識するようにしているのですが、やってもドメイン駆動設計にするだとかFlux使ってみるだとか表面的な話ばかりで、実際のデータ管理の所までは考えきれていませんでした。今、間違えた場所を記録できるタイピングアプリのようなものを作っているのですが、実際に使ってみようと思います。

「Stripe触ってみた! 〜Jekyll + AWS S3に組み込み〜」(Tokunology 徳納さん)

簡単に決済の設定から、QRコードを作成して投稿できるデモを見せていただきました。テスト環境ではなく、ちゃんと決済出来るようになっていてさすがです。

あとで、「Google Chart API」で簡単にQRコードを発行できることを教えてもらいました。僕が発表した「20時間で作る中古本プラットフォーム」では、下のサイトを使っていたのですが、表示に時間がかかり悩んでいました。僕の発表では、結構無計画なLTをしてしまいましたが、こんな話が聞けてLTやってよかったと思えました。誰かに見せるの重要だなとしみじみ感じさせられました。

goqr.me

「20時間で作る中古本プラットフォーム」(@gpioblink)

ここからは、僕がLTで発表した「20時間で作る中古本プラットフォーム」について説明していきます。

レシートプリンターを使いたかったこともあり、サーバーサイドは中古本書店のローカル環境でサーバーを動かす前提で作っていました。そのため、残念ながらデモサイトはありません。。ソースコードはこちらからどうぞ!(サーバーの方はまだしも、フロント側のコードは参考にしないでください🤐。とりあえずタイマー代わりに無限ループしてたりいろいろメチャクチャです。。)

github.com github.com

最近、コードを書き始める前に、全体の設計を紙に書くようにしています。個人的な話ですが、これがあると自分がどこにいるかすぐに分かり開発効率が上がります。

今回は、こちらで紹介されているCleanMonolithアーキテクチャのサンプルコードを元に拡張していく形で開発を進めました。

threedots.tech

そのため、設計の土台はサイトで紹介されている全体図をベースにして書き込んでいきました。

f:id:gpioblink:20200304115159p:plain f:id:gpioblink:20200304115713p:plain

主に今回やったことは次の通りです。

  • Printer関係のマイクロサービスを追加して、「決済済みの注文情報からレシートを印刷する」ユースケースの作成
  • 決済プロバイダーのモックをStripeと接続できるように変更
  • 決済完了時の副作用としてStripeのwebhookを受け取れるように変更

当初はこの3つの予定でしたが、StripeのCheckout時に送信するMetaDataをうまく追加できませんでした。そのため、Stripe側とサーバー側の決済情報を一致させるために

  • サーバー側の注文IDとStripe側の決済IDを関連付けるデーターベースの作成と、使用するためのユースケースの作成

を追加で行なっています。

実際に20時間のペース配分がどうだったのか(予定では15時間だったが結局20時間していた)は、下のスライドでぜひ見ていってください。

docs.google.com

うまくプリンター部分が完成しておらず、本番では謎の文字化けコードが出力されたりしていました。goからうまくプリンターが見えていないようで、execとかでとりあえず動くように急いでいましたが残念ながら間に合いませんでした。PHPPythonにあるライブラリではうまく行くのですが。。同期のAndroidエンジニア@yt8492などから、この部分だけPHPで切り出せばとアドバイスをいただきました。マイクロサービス風の設計をしているので、これを思いつかなかったのはちょっと情けなかったです。。今度これを拡張した在庫管理アプリを作る予定なので、そこでプリンターを扱う部分を書く際に一緒に直したいと思います。

f:id:gpioblink:20200304120659p:plain
謎の文字化け中国語が出てきたサーマルプリンター(レシートは撮り忘れた。。)

編集後記

最近、情報に溢れてしまうからとTwitterをあまり投稿したり見ないように個人的に制限をかけていますが、過去のイベントのログを取る意味ではめちゃくちゃ便利ですね!

ハッシュタグだけでイベントを振り返れました!!昔はLTのときだけTwitterする人とか名乗っていましたが、それも悪くないかもしれません。現在、Twitterをメンションか自分から発信したい内容があるときしか使わないようにしています。今後は、ちょっと範囲広めて、イベントの時は積極的に使って行こうと思います。