Shogo's Blog

Nov 23, 2016 - 1 minute read - qrcode

Twitterの二次元コード問題と、QRコード・フレームQRの見分け方

先日Twitterの公式アプリがQRコード® (お店やお友達を簡単にフォローするために) の作成と読み取りに対応しました。 しかし、生成されるQRコードが標準規格に準拠していないため、 「他のリーダーで読めない」「法的に問題があるのでは?」等々の指摘が出ていました。 人事ながらTwitterさんのことが心配になったので少し調べてみました。 なお、僕は法律の専門家ではないため、本記事の正確性は保証できません。 あくまで個人的な見解なので、 実際にQRコード®を使用するさいは各自の判断でお願いします。 指摘ツイート Twitterが生成するQRコード、規格(JIS X 0510・ISO/IEC 18004)を大幅に逸脱しているので「QRコード®」を名乗ること自体に法的なリスクがある。 — 祥太(4/15レイフレ18 C19+20) (@shota_) 2016年11月17日 「デンソーウェーブは、JIS、ISOの規格に沿ったQRコードに限っては特許権を行使しませんが、規格を逸脱したQRコードについてはこの限りではございませんので、特許権を行使させていただくこともございます。」 (出典: https://t.co/SKXgBGSb8E ) — 祥太(4/15レイフレ18 C19+20) (@shota_) 2016年11月17日 明暗暗転で読み取らないという話を多数見かけますけど、そちらについては「ISO/IEC 18004からは逸脱」「JIS X 0510には準拠」(規格票7.3.8参照)という微妙な状況なのです。多分ISOには準拠しているのでアプリは悪くないと思います。 — 祥太(4/15レイフレ18 C19+20) (@shota_) 2016年11月17日 たしかに qrcode.comのFAQには 特許について以下の記述があります。 色を付けたりイラストを入れるような使い方をしても問題ありませんか? (中略) また、QRコードにイラストを重ねたりデザインを乗せるということは、QRコードの規格から外れ「QRコードではないもの」となってしまう可能性がございます。 デンソーウェーブは、JIS、ISOの規格に沿ったQRコードに限っては特許権を行使しませんが、規格を逸脱したQRコードについてはこの限りではございませんので、特許権を行使させていただくこともございます。 2022-06-05追記: 改めてqrcode.comのFAQを確認したところ、以下のように文言が変更されていました。 色を付けたりイラストを入れるような使い方をしても問題ありませんか? QRコードにイラストを重ねたり、デザインをのせて変形してしまうと、ちょっとした汚れや欠けでも読み取りが出来なくなったり、読み取りの反応が悪くなってしまうことがありますので推奨しておりません。 安定した読み取りという面から、JIS、ISOの規格で制定されている内容に従ってご利用いただくことを推奨しております。 なおイラストやデザインを施すような使い方をご希望の場合は、デンソーウェーブのフレームQR®をご利用ください。 特許権の行使についての文言が削除されています。 2017年1月28日で特許権が有効期限切れになり、デンソーウェーブが特許権を行使することができなくなったからだと思います。 このことから特許についてはクリアになったと言えるでしょう。 とはいえFAQにあるとおり、読み取り性能の観点からイラストを入れるのは非推奨、という点は変わりありません。 追記ここまで 問題点 公式アプリの生成する二次元コードは以下のような問題があります。 データパターンの20%近くがアイコンで上書きされている 「アライメントパターン」がTwitterのロゴで欠けている 明暗暗転している(一応JISには沿っているらしい) 法的リスク以前に、 読み取り性能/互換性が劣化するので使わない方が無難でしょう。 自分のプロフィールのURL (僕の場合は https://twitter.com/shogo82148 )を QRコードに変換すれば公式アプリのリーダーでも読めるので、 こちらの方がオススメです。 QRコード関連の権利 特許 QRコード®のJIS規格JIS X 0510には、 関連する特許として特許第2938338号「二次元コード」があげられています。 ただし、特許の保護期間は20年なので、1994年に出願されたこの特許は2014年で消滅しています。 したがってこの特許を理由に訴えられることはなさそうです。

Jun 10, 2016 - 1 minute read - web

GitHub Pagesがhttpsをサポートしたので切り替えてみた

このブログを設置しているGithub PagesがHTTPSに正式対応したらしいので、HTTPSを強制するように設定してみました。 HTTPS for GitHub Pages やったこと ページ内にHTTP経由で取得したリソースが含まれていると、 警告が出たり取得自体がブロックされたりしてしまうので、 全てHTTPS経由で取得するように書きなおす必要があります。 画像・CSS・Javascript等のURLを、以下のようにnetwork-path referenceへの置き換えましょう。 HTTPでページを開いた場合はHTTPで、HTTPSでページを開いた場合はHTTPSで、リソースを取得してくれます。 <a href="http://google.co.jp"> <a href="//google.co.jp"> このサイトはHTTPのレンダリングにOctopressを使っています。 最新版のOctopressではnetwork-path referenceを使ってくれるので特に対応は不要です。 このサイトの場合は古すぎてHTTP参照だったので、 「Octopressをアップデートした」を参考にしてアップデートしました。 はてなブックマーク連携など、自分でカスタマイズした部分に関しては手作業で対応したました。 HTTPS強制の設定 Securing your GitHub Pages site with HTTPS どおりに設定を有効化すればOKです。 ユーザ毎ではなくプロジェクト毎の設定のようなので、 プロジェクト用のページを作っている場合は個別に設定が必要です。 はてなブックマークについて HTTPとHTTPSは別URLとして扱われるようなので、過去の記事に対するはてブ数はリセットされてしまいます。 解決方法は無いかと調べてみたものの、現象無理っぽいです。 自分のブログは http から https に移行したけど、記事についたはてブを移行することは出来なかった(はてなのサポートに聞いた)。分からないでもないけど、https 移行の躊躇材料になるという点においてはイケてない。 — Takashi Masuda (@masutaka) 2016年6月6日 はてなさんの方で対応してくれないかな・・・ 2016/06/30追記: DISQUSのマイグレーション 記事にコメントをつけるのに使っているDISQUSをマイグレーションするのを忘れてて、 過去のコメントが見れなくなっていたので追記。 DISQUSのホームから「Admin」「Edit Settings」で設定画面を開き、 Website URLの近くの「Changing domains? Learn how.」をクリックします。 すると「Migration Tools」が開くので、「Start URL mapper」「you can download a CSV here」をクリック。 5分くらいするとDISQUSがコメントを管理しているURL一覧がメールで届くので、 それを元に新旧URLの対応表を作ります。

Apr 13, 2016 - 4 minute read - go golang

net/httpで安全に静的ファイルを返す

net/httpで静的ファイルを返すで、 http.ServeFileを使っていてアレ?と思ったのでちょっと詳しく調べてみました。 (http.FileServerを使うものだと思ってたため) 結論だけ先に書いておくと やはり、特に理由がなければhttp.FileServerを使ったほうが良さそう どうしてもhttp.ServeFileを使う場合は定数でパス指定をする 「自作パスルータを使っている」かつ「Go 1.6.1 未満を使っている」場合はとくに要注意 ディレクトリトラバーサル脆弱性 紹介されているのは以下のコードです。 http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, r.URL.Path[1:]) }) しかし、参照先の「Go Golang to serve a specific html file」には Actually, do not do that. (やっちゃいけない)とコメントされています。 ディレクトリトラバーサルにより 脆弱性の原因となってしまう可能性があるためです。 脆弱性再現のために、以下の様なコードを書いてGo1.5でコンパイルして実行してみました。 package main import ( "net/http" "strings" ) func main() { http.ListenAndServe(":3000", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/static/") { http.ServeFile(w, r, r.URL.Path[1:]) } else { http.NotFound(w, r) } })) } ..を含んだパスをリクエストしてみます。(実行した場所によって..の数は変わるので適宜調整してみてください)

Apr 6, 2016 - 1 minute read - polyglot perl go golang

PerlでもGoでも実行できるQuine書いた

昨日のPolyglotを元にPerlでもGoでも実行できるQuine書いた。 package main;import("fmt");var(q=`printf'package main;import("fmt");var(q%c%c%s%c/*%c);sub import{}sub var{$_%cshift%c~s!%c(.*)%c/\*!$1!gr;eval}%c__END__%c',61,96,$_,96,61,61,61,96,96,10,10;print<DATA>`/*=);sub import{}sub var{$_=shift=~s!`(.*)`/\*!$1!gr;eval} __END__ */);func main(){s:=`package main;import("fmt");var(q=%c%s%c/*=);sub import{}sub var{$_=shift=~s!%c(.*)%c/\*!$1!gr;eval} __END__ */);func main(){s:=%c%s%c;fmt.Printf(s,96,q,96,96,96,96,s,96)} `;fmt.Printf(s,96,q,96,96,96,96,s,96)} Perlで実行してもGoで実行しても自分自身を出力します。

Apr 5, 2016 - 1 minute read - polyglot perl go golang

PerlとGolangで実行できるPolyglot書いてみた

Rubyの会社をPerlの会社に変えてしまおう計画。 Golangのフリをして忍び込ませれば行けるのではという話になったので、 GoでもPerlでも実行できるコードを書いてみた。 出来上がったのがこちら。 package main; import ("fmt"); var (s=0/*==); sub import {} sub var { print "Hello macotasu"; } __END__ */) func main() { fmt.Println("Hello macotasu") } 一番のポイントはvar (s=0/*==);の行ですね。 Perlで解釈すると正規表現置換s///として解釈され、/*が無視されます。 Goで解釈すると変数sへの代入として解釈され、/*がコメントとして扱われます。 あとはGoのキーワードをPerlが解釈できないので、ちょっと書き方を工夫します。 package main はGoでもPerlでも似たような意味で解釈されるのでそのまま Goの import, var はPerlで解釈できないので、()を省略せずに書いてPerlの関数呼び出しっぽくする 省略可能なセミコロンをちゃんと書く GoとPerlのコードは分かれているのでどんな処理でも自由に書くことができますが、 import だけGoでもPerlでも解釈されてしまうというという制限があります。 import するパッケージが一個だけなら問題ないんですが、 複数書く場合は以下のように2個め以降をすべてドットインポートする必要があって男気あふれる感じです。 (Perlでは文字列結合として解釈される。Goではvarのあとにimportかけないっぽいので、ここに押し込むしかない。) package main; import ( "fmt" . "math" ); var (s=0/*==); sub import {} sub var { print "Hello macotasu"; } __END__ */) func main() { fmt.

Mar 29, 2016 - 1 minute read - javascript

Webブラウザを使って電波を出してみた

読者の持っている至って普通のコンピューターは、実は電波時計の時刻合わせを行うために必要な標準電波の発信装置が備わっている。 コードは以下から入手できる。 shogo82148/web-jjy JJYシミュレータWeb版 動かし方 パソコンのイヤホンジャックにアンテナ(普通のイヤホンで十分です)を接続し、電波時計の近くに置きます。 音量を最大にし、「Start」ボタンを押すと信号が送信されます。 電波時計を強制受信モードにし、時刻が設定されるのを待ちましょう。 パソコンの時間を基準にするので、あらかじめntpとかで時刻設定をしておくといいと思います。 原理 標準電波JJYは日本標準時のタイムコードを送信する電波で、 東日本では40kHz、西日本では60kHzの周波数で発信されています。 電波時計はこの信号を使って時刻合わせをしています。 この信号をオーディオデバイスから出力する電波時計用JJYシミュレータというものがあるのを知り、 「今のWebブラウザならjavascriptだけで実装できるのでは?」と思いやってみました。 一般的なオーディオデバイスは、20kHz以上の周波数の再生には適していないため、そのままでは40kHz/60kHzの信号は出せません。 そこで、電波時計用JJYシミュレータは、歪んだ波形に含まれる高調波を利用しています。 ボリュームを大きくして音が割れた状態になると、音声信号は矩形波に近いかたちになります。 矩形波には3倍、5倍、7倍…の奇数倍の周波数成分が含まれているため、 (世はまさに大フーリエ時代とか見ると楽しい) 13.333kHzの矩形波を出力することで、39.999kHzの信号を出せるというわけです。 元のソフトウェアはWindowsのバイナリ形式でしたが、 WebAudioの登場によりWebブラウザからも同様のことが行えるようになりました。 最後に 少し前にCPUから出るノイズを使ってAMラジオの電波を発信するという記事が話題になりましたね。 普通のコンピューターからAMラジオを鳴らそう CPUやオーディオデバイスも電気で動いている以上、電波が出ているのは当たり前のことなのですが、 こうやって改めて確認できると面白いですね。 パソコンから出る程度の電波強度では、電波法に抵触することはないと思いますが、 うっかり強力な電波を発信しないよう気をつけてください。

Mar 23, 2016 - 1 minute read - go golang

数値と文字列がごちゃ混ぜになっているJSONをよしなにParseするやつ作った

Goは数値と文字列を厳格に区別しますが、他の言語もそうとは限りません。 例えばPerlは数値と文字列を自動変換してくれるので、気をつけていないといつの間にか数値が文字列になっていたりします。 その言語の中に閉じていいれば問題ないのですが、Goとやり取りしようとすると困ります。 そんなときに使えるライブラリを書いてみました。 shogo82148/go-weaktyping 背景 map[string][]*stringを返してくるライブラリがあって、 そのままだと扱いにくいのでなんとか構造体にできないかと頭を悩ませていました。 JSONに一旦変換すれば楽かなーとも思ったのですが、一部フィールドを数値に変換する必要がありました。 JSONの数値と文字列を区別するため、JSONの文字列をGoの数値型に変換するのは厄介です。 タグにjson:",string"と指定すると変換可能になりますが、逆にJSONの数値を受け付けなくなりますし、 JSONに変換すると文字列になってしまいます。 変換先の構造体は普通のJSONの操作にも使いたかったので、これでは困ります。 「数値も文字列もUnmarshalできて、Marshalするときには数値になる」ようなJSONライブラリが必要でした。 "encoding/json"に代わる新しいJSONライブラリを・・・とも考えたのですが、 よく考えるとUnmarshal時の挙動は"encoding/json".Unmarshalerインターフェースを実装することでカスタマイズ可能です。 こうして作ったのが go-weaktyping です。 使い方 builtinの型の先頭を大文字にしたものを用意しているので、 適当にUnmarshalして欲しいところでbuiltinの型の代わりに指定するだけです。 以下は整数型をUnmarshalする例です。 package main import ( "encoding/json" "fmt" "log" "github.com/shogo82148/go-weaktyping" ) func main() { ptr := &struct { Foo weaktyping.Int `json:"foo"` }{} if err := json.Unmarshal([]byte(`{"foo":123}`), ptr); err != nil { log.Fatal(err) } fmt.Println("Foo:", ptr.Foo) if err := json.Unmarshal([]byte(`{"foo":"456"}`), ptr); err != nil { log.Fatal(err) } fmt.Println("Foo:", ptr.Foo) } {"foo":123}が正常にUnmarshalできるのはもちろん、 通常はエラーになってしまう{"foo":"456"}のUnmarshalも問題なく行えます。 Marshal時は通常のint型と同様に振る舞います。

Mar 18, 2016 - 2 minute read - perl redis

Redisのトランザクション・スクリプト・ランキングを扱うPerlモジュールを公開しました

以前Redisでスコアを複数設定できるランキングを作ってみたけど、 Githubの肥やしになっていてもあれなので、CPANizeしました。 あわせて、この実装のために作ったユーティリティモジュールも別モジュールとして公開しました。 Redis::LeaderBoardMulti Redis::Script Redis::Transaction Redis::LeaderBoardMulti 最初の基準で順位を決められなかった場合の第二基準が欲しいというときに使うモジュールです。 インターフェースがRedis::LeaderBoard互換になるように調整したので、 前回とインターフェースがちょっと変わっています。 se Redis; use Redis::LeaderBoard; my $redis = Redis->new; my $lb = Redis::LeaderBoardMulti->new( redis => $redis, key => 'leader_board:1', order => ['asc', 'desc'], # asc/desc, desc as default ); # Redis::LeaderBoardに合わせて複数指定できるようになりました $lb->set_score( 'one' => [100, time], 'two' => [ 50, time], ); my ($rank, $score, $time) = $lb->get_rank_with_score('one'); Redis::LeaderBoard互換なのでそのまま入れ替えられるはずですが、以下のような実装上の制限があります。 スコアはすべて64bit符号付き整数 Redis::LeaderBoardのスコアは倍精度浮動小数点型なので小数も扱えるが、Redis::LeaderBoardMultiは整数だけ Redis 2.8.9以降のみで動きます 同順の場合の出現順 Redis::LeaderBoard は ZRANK, ZREVRANK を使い分けているので、orderパラメータによって昇順/降順が変わります Redis::LaederBoardMulti は ZRANK しか使わないので、必ず昇順になります 一応 Lua Script を使わないオプションもそのまま残してありますが、特に理由がない限りデフォルト(Lua Script を使う)で使うといいと思います。 どうしてもロックの範囲が広くなってしまう場合があり、楽観的ロックでは効率が悪いケースがあるためです。

Mar 14, 2016 - 2 minute read - go golang websocket

ngrokみたいなHTTPプロキシを書いてみた

開発中のWebアプリをみんなに試してほしいけど、 サーバなんてなくて開発環境がローカルにしか無くて公開できないということは、 開発初期段階だとよくあることだと思います。 もちろん本格的にやるならテスト用にサーバを建てるべきですが、 小さなものならngrokを使うと簡単です。 ngrokの公開サーバへのHTTPリクエストをローカルにリレーして、 ローカルのサーバをお手がるに公開できるサービスです。 びっくりするほど簡単に公開できて便利ですが、 一応oAuthで制限とかかけたいなーとかカスタマイズしてみたくなってきたので、 似たようなものを自作できないかといろいろ遊んでみました。 その結果、HTTP2 over Websocketみたいな謎なものが出来上がってしまったというお話です。 HTTP2 over Websocketというアイデア ngrokっぽいものを実現するためには、 サーバが受け取ったHTTPリクエストをローカルの環境に転送する必要があります。 ご存知のとおり通常のHTTPではサーバ側からのプッシュ配信が難しいので、Websocketを使うのが良さそうです。 しかし、複数のコネクションで並列にやってくるHTTPリクエストを、一本のWebsocketに束ねる必要があり、 上手く制御するのは大変そうです。 さて、HTTP2は一つのTCPコネクションで複数のリクエストを並行処理する仕様があります。 「複数のリクエストを一本に束ねる」という点ではなんか似ているので、なんだか流用できそうな気がしてきました。 Golangならきっと上手いことinterfaceを実装すれば、なんとかできるのではとやってみました。 実装 HTTP2は暗号化や複雑なフロー制御を行っていますが、 外から見ればnet.Connインターフェースに読み書きしている何かに過ぎません。 そして、websocket.Connもnet.Connを実装しているので、そのままHTTP2のライブラリに渡せるはずです。 そうしてできたのが以下のサーバです。 package main import ( "errors" "log" "net/http" "net/http/httputil" "sync" "golang.org/x/net/http2" "golang.org/x/net/websocket" ) type transport struct { m sync.Mutex t http.RoundTripper closed chan struct{} } var t *transport func main() { t = &transport{} s := websocket.Server{Handler: websocket.Handler(Handler)} http.Handle("/", s) go http.ListenAndServe(":3000", nil) http.

Mar 10, 2016 - 1 minute read - go golang

nginx-omniauth-adapterのGolangポート作った

「nginx で omniauth を利用してアクセス制御を行う」という記事で、 ngx_http_auth_request_moduleの存在を知ったので、 Golangでnginx_omniauth_adapterと似たようなものを作ってみました。 shogo82148/go-nginx-oauth2-adapter 背景 typester/gateは単体でも動くようになっていますが、 例えばIP制限などちょっと高度なことをしたい場合には結局nginxを前段に置く必要があります。 nginxとgateの設定を同時にいじる必要があって煩雑だと感じていました。 そんな中「nginx で omniauth を利用してアクセス制御を行う」という記事で、 ngx_http_auth_request_moduleの存在を知りました。 gateが認証+Proxyをやってしまうのに対して、認証だけRubyのomniauthモジュールで行いProxyはnginxに任せるという方法です。 以前から記事の存在は知っていたのですが、Rubyの実行環境をそろえるのが億劫で手を出せずにいました。 小さなアプリなので自分の慣れた言語で実装しても大したことないのではと思い、Goで実装してみることにしました。 使い方 go getで落として来れます。 最低限client_idとclient_secretの指定が必要です。 nginx_omniauth_adapterと同じ環境変数名で設定できるほか、YAML形式の設定ファイルを読みこませることができます。 YAMLの形式はREADMEを参照してください。 $ go get github.com/shogo82148/go-nginx-oauth2-adapter/cli/go-nginx-oauth2-adapter $ export NGX_OMNIAUTH_GOOGLE_KEY=YOUR_CLIENT_ID $ export NGX_OMNIAUTH_GOOGLE_SECRET=YOUR_CLIENT_SECRET $ go-nginx-oauth2-adapter $ go-nginx-oauth2-adapter -c conf.yaml # 設定ファイルでの指定も可能 PerlでHTTPサーバ書いているひとにはおなじみのServer::Starterにも対応しているので、 それ経由で立ち上げておくと設定の更新・プログラム自身の更新等が楽になると思います。 start_server --port 18081 -- go-nginx-oauth2-adapter -c conf.yaml nginx側の設定はexamplesディレクトリを参照してください。 ヘッダ名・パス名等を合わせてあるので、nginx_omniauth_adapterと同じ設定で動くはずです。 また、h2oの設定はプログラマブルだからh2oでもちゃんと設定ファイルを書けば動くのではと考え、 h2oの設定も書いてみました。 mrubyからproxyに渡るリクエストを書き換える方法がない(?)っぽいので、アプリ側で認証情報をとることはできないですが、一応制限はできます。 basic認証の実装を見る限りremote-userヘッダだけは渡せるようなので、これを使えばなんとかなるかもしれないですが、未確認です。 (Ruby慣れてないからってGoで実装したけど、結局Rubyを書いていて面白い) nginx_omniauth_adapterとの違い 厳密に同じ挙動を実装するのが面倒だったため、挙動に若干の違いがあります。 一番大きなものは認証後のリダイレクト先です。 nginx_omniauth_adapterは認証後、一度adapterのURLにリダイレクトしてから、アプリサーバの/_auth/callbackにリダイレクトします。 それに対してgo-nginx-oauth2-adapterは認証後、アプリサーバの/_auth/callbackに直接リダイレクトします。 この違いのため、Google Developers Consoleの「承認済みのリダイレクト URI」に設定するべきURIが異なることに注意してください。 nginx_omniauth_adapterはadapter自身のURI、go-nginx-oauth2-adapterはアプリサーバの/_auth/callbakを指定します。 この挙動のため、go-nginx-oauth2-adapterはアプリの追加のたびにnginxの設定に加え「承認済みのリダイレクト URI」に正しいURIを追加する必要があります。 もちろん設定箇所がGoogle Developers Consoleではないだけで、nginx_omniauth_adapterもリダイレクト先の設定は必要です。 GoogleでもFacebookでも認証できるようにしたいという場合、nginx_omniauth_adapterは設定を一箇所変えればOKですが、go-nginx-oauth2-adapterは各サービスに登録し直す必要があります。 現状、認証に使うサービスをユーザが選ぶ仕組みがないので、そのまま放置してあります。