CORSこんにちは、AWS担当のwakです。できない理由を書きます。Sharing)についても簡単に解説します。猫もおてあげやりたかったこととあるデータ(刻々と追加されていきます。更新はなし)をDynamoDBに溜め込んでいます。Lambdaで実装しました。ところで、これらのデータは1日単位でS3にJSON形式で書き出してアーカイブとして保存してあります。検索条件が日付だけなら、わざわざDynamoDBを見るまでのこともありません。「S3のこのURLを見てね」と言えばいいだけです。いうことができると都合がいいわけです。OtherでS3にリダイレクトする3番目は無理でした、というのが今回の記事の趣旨になります。以下、その説明をします。Policy(同一オリジンポリシー、同一生成源ポリシー)というルールがあります。ここでは「オリジン」が何かはちょっと後回しにして、次のようなシナリオを考えてみます。いう社内Webサーバーがあるとします。このWebサーバーは外部には公開されていません。悪い人がいて、どこからかこのURLを入手したとします。いうWebページをインターネット上に作り、何らかの方法*1で私にアクセスさせます。このWebページにはJavaScriptが書いてあります。スクリプトはWebページを開くと同時に勝手に上記のURLにXHRでアクセスし、取得したデータを全て外部に送信してしまいます。このようなことではいけません(私は死にたくありません)。この秘密のデータを他のWebサイトから参照したいような状況もありますが、少なくとも全ての外部Webサイトのスクリプトからアクセスできる必要はまったくありません。そこで、スクリプトは原則として「同一のオリジン(場所)」にあるリソースにしかアクセスできないというルールができました。これが同一オリジンポリシーです。オリジンとはオリジンという言葉が突然出てきましたが、これは大ざっぱに言えばドメインのことだと理解すればいいです。6454で定義されていて、HTTP/HTTPSの区分FQDN(example.comとか、www.example.comとか)ポート番号をセットにしたものです*2。http://evil.com上にあるスクリプトは、次のような場所にあるリソースにはアクセスできないわけです。http://mycompany.local(ドメインが全然違う)https://evil.com(同じに見えるけどHTTPとHTTPSが違う)http://evil.com:8080(ポート番号が80番と8080番で違う)http://www.evil.com(これも別扱い)これだけ厳密なチェックが入るなら安心ですね。Sharing)ところが、異なるオリジンをまたいで外部リソースを参照することが一切許されないのでは不都合なことも多々出てきます。そこで、リソースが置いてある側、つまりmycompany.local側で事前に設定を行い、どのようなタイプのリクエストなら許可するかをホワイトリスト形式で指定することになりました。Sharing)です。具体的には、ブラウザからのリクエストに応じ、リソースを置いてあるサーバーがHTTPヘッダで「どこからのアクセスなら許可するか」「リクエスト時に含まれていても良いHTTPヘッダ」のような項目を回答します。ブラウザはこの値をチェックし、リクエストの内容がそれとマッチするときにだけアクセスを許可します(そうでないならアクセスをブロックしてネットワークエラーを発生させます)。この制御により、リソースの所有者の意図、ブラウザの利用者の意図に反してアクセスが行われてしまうことを防ぐわけです。余談:CORSは何でないかCROSはあくまでブラウザが(いわば)自主規制をするだけのもので、ユーザーが意図的に発生させたリクエストをブロックするようなものではありません。悪意を持って作成されたスクリプトを実行してしまっても、リソースの所有者やユーザーが意図しないうちに勝手にリクエストが発生してしまう(発生させられてしまう)ことを防ぐための仕組みです。セキュリティについてはサーバーサイドできちんと考える必要があります。2種類のクロスオリジンリクエストこのように、アクセス元のオリジン(上記の例ですとhttp://evil.com)、リソースのあるオリジン(同じくhttp://mycompany.local)とが異なる場合のアクセスはクロスオリジンリクエストと呼ばれます。ブラウザはこのリクエストを2種類に分けて扱います。request)とは、特定のHTTPヘッダのみ・特定のContent-Typeの値のみを持つGET/POST/HEADリクエストです(詳しくはリンク先を読んでください)。jQueryでこのようなコードを書いた場合がこれに該当します*3。console.log(data);});スクリプトが「シンプルなクロスオリジンリクエスト」を送信した場合、ブラウザはまずレスポンスヘッダの中からAccess-Control-Allow-Originヘッダの値を確認します。その値が元のオリジンと一致すれば(*やhttps://*.example.comなどのワイルドカードも使用可)そのアクセスは認められることになります。逆に一致しないか、そもそもAccess-Control-Allow-Originヘッダがなかった場合、そのアクセスはブロックされてしまいます。シンプルではないリクエスト前項のシンプルなクロスオリジンリクエストではないリクエストは全てこれです。認証のためにAuthorizationヘッダやX-Api-Keyヘッダを付加する場合、PATCHリクエストやDELETEリクエストを送信する場合などが該当します。BASIC認証が必要なURLにアクセスするため、jQueryで次のようなコードを書いたとします。console.log(data);});この場合、ブラウザはGETリクエストに先立ち、同じURLに対して自動的にOPTIONSリクエストを送信します。これはプリフライト(preflight)と呼ばれ、スクリプト側からは制御できず強制的に行われます。クロスオリジンリクエストを受け付けたいWebサーバーは、このOPTIONSリクエストに対して「どのようなリクエストなら受け付けても構わないか」を返答しなければなりません。返答は全てレスポンスヘッダで行います*4。(Node.js)のコードを呼び出し、そのまま結果を返すか、またはS3へリダイレクトすることを考えます。integrationを使うことを前提にします。リクエストはGETを利用します。ブラウザが前述の「シンプルなクロスオリジンリクエスト」を送信してきて、かつリダイレクトを行わない場合です。Lambda側の処理はこうなります。}});ブラウザはここでセットしたAccess-Control-Allow-Originヘッダの値を確認し、アクセス元のオリジンと一致するかどうかを調べて、問題がなければアクセスを許可します。Gateway側のCORS設定は使用されません。Gatewayが勝手に応答します*5。*という内容が含まれていて*6、ブラウザは最初のチェックを行います。このチェックをパスしたら、ブラウザは改めてGETリクエストを送りますが、後の処理は前項(A)と同じです。再度Access-Control-Allow-Originのチェックがかかるところも変わりません。可能ですが制約が厳しくなります。Gatwayは303を返します。ブラウザはAccess-Control-Allow-Originをチェックした上でリダイレクト、つまり指定されたS3へ再度GETを送ります。ところがこの2回目のGETでは、ブラウザはオリジンとしてnullを使用します*7。この挙動はRFCで規定されています*8。*を返す必要があります。CORSでのアクセス制御がかけられないことを意味していて、重要なデータを扱うには非現実的になります。シンプルではないクロスオリジンリクエスト&リダイレクトを行う場合ダメです。Recommendationにはこのような記述があります。steps.つまり、このような処理が行われます。最初にブラウザはプリフライトリクエストとしてOPTIONSリクエストを送信します。レスポンスにはAccess-Control-Allow-Originも含まれます。次にブラウザはGETリクエストを送信します。Otherを返します。ブラウザは無条件で通信をキャンセルします。Key認証を行うためにはリクエスト時にX-Api-Keyヘッダを含める必要があります。このヘッダを含めた場合、リクエストは「シンプルなクロスオリジンリクエスト」ではなくなってしまいます。するとCではなく)のパターンになり、ブラウザは仕様上通信を行うことができません。CORS」の設定を行ったときに追加されたOPTIONSメソッドの設定に従ってレスポンスが送信されます*6:"*"はデフォルト値です。読者になるもっと読むコメントを書く2017-01-20Slackにスレッド表示機能が追加されましたSlackこんにちは、Slack大好きなwakです。Slackにスレッド表示機能が追加されたと聞いてさっそく使ってみた雑感を書きます。概要これまでと画面が大きく変わるわけではありません。replies」とカウンタが増えていく。Threads」に通知が来ます。参加するためにはいくつかの方法があります。このスレッドで決めましょう」と書き、その発言を開始点としてスレッドを作って、その中で参加者にメンションを飛ばすとすればいいことになります。留めされたスニペットとの違い弊社ではゴルフ場様向けに様々なサービスを開発・提供しており、お客様からのお問い合わせも数多くいただきます。そのインシデント管理はSalesforceを活用しているのですが、担当者だけでは解決しなかった場合、別の詳しいメンバーや開発担当等にエスカレーションし、ヘルプを求めます。それを多数のメンバーでスピーディに行うためにSlackを活用しており、サポートチャンネルにその旨をスニペットで*1書き込んでピン留めし、簡易的な課題管理のような使い方をしています。留めされたスニペットや画像は、そのチャンネルに入っている全員が見える現在未解決のまま残っている問い合わせが一目で分かる*2コメントをスレッド形式で書き込んでいける進捗や担当・開発者間のやり取りも当初の問い合わせ内容の下にぶら下げて書けるというメリットがあります。こんな感じになります。スレッド表示もこんな感じで使えると良いかと思ったのですが、スレッドに参加する・参加させるというステップが必要なこともあり、現在のところはもっと軽い使い方になりそうです。チャンネルに参加している人数の多寡によってもありがたみは変わってきそうだと感じました。数百人といった大きなチャンネルでの使い勝手も聞いてみたいところです。それでは良いチャットライフを。*1:一言二言で終わるような問い合わせはないため、これは自然な行動です*2:インシデント管理は別途Salesforce+Remedyforceで行っているため、これはあくまで現状を簡単に確認するためのものです。言うまでもありませんが、解決したらピン留めは外します。読者になるもっと読むコメントを書く2016-12-21石器時代みたいなWebアプリ開発をしていたエンジニアがReact.jsに導かれて2016年にやってきた話はじめに社内向けのシンプルなWebアプリケーションを作成することになりました。求められているものはサービスそのものであり、実装方式については全て自分で決めていいわけですが、この際なので2016年のモダンな開発方法で書こうと思い立ちました。そこでReact.jsを採用します。今回の記事はその日記のようなものです。Babelファイル監視Browserify古き良き時代Node.jsではどうやっているかそこでBrowserify例1例2終わりにこの記事のまとめReact.jsを使い始めました。そのためにnpmとBabelを入れました。ついでにgulpとBrowerifyを入れました。快適かつモダンな開発環境を手に入れました。2016年を代表する猫まずReact.jsについてReact.jsってなにFacebookの偉大なエンジニアが作ったフロントエンド用のフレームワークです。特徴として、DOMを全てJavaScriptで構築・操作する(基本的には)データの流れが一方通行コードをReact.js独自の文法「JSX」で記述するが挙げられます。DOMHTMLを書くのはやめます。DOMは全てJavaScript側で構築してHTMLに流し込みます。動的に操作するのももちろんJavaScriptです。src="./lib/app.js"></script></body>こんな風に超シンプル(というより空っぽ)になります。id="app">読み込み中...</div>が丸ごとJavaScript側で生成したDOMに置き換わるわけです。通行jQueryを使ったDOM操作でWebアプリケーションを作るとき、たとえば画面の右側(例:アイテムの絞り込み条件)と左側(例:アイテムの一覧表示)で不整合が起きるようなバグに苦しむことがあります。これは画面の要素のあちこちが独自に状態を抱え込み、しかもその要素が複雑に絡み合って情報を受け渡しするため、その管理を正しく行うのが難しくなるからです。画面に表示すべき全てのデータを1個のオブジェクトにまとめてしまうそのオブジェクトを受け取って画面表示する(=DOMに変換する)処理を書くという基本原則があります。画面を書き換えたい場合は、オブジェクトの値を更新する全ての画面要素を一括で描画し直すで済ませてしまいます。このルールにより、画面表示と内部データは常に一貫性を持っていることが保証されます。DOMと呼ばれています)、処理は高速に行われます。差分がなければDOM操作は発生しません。JSXここからが本題です。React.jsのコードはJSXという文法で記述します。これはJavaScriptを拡張した独自の文法で、JavaScriptに似ていますがJavaScriptではありません(明らかに文法エラーになります)。document.getElementById('app'));JavaScriptのコード中にHTMLのタグが出現しています。これは、1行目で独自のAppというタグ(コンポーネントと呼びます)を定義し、2行目でAppコンポーネントを新しく生成し、HTML側のdivタグに流し込むという処理です。コンポーネントはいくらでも作ることができます。React.jsでは、Webアプリケーションを構成する要素をこのコンポーネントに分解し、それらを組み立てることでDOMを構築していきます。JSX→JavaScriptの変換をしたいJSXはFacebookの偉大なエンジニアが勝手に定義した言語ですので、ブラウザは解釈できません。したがって、JSX→素のJavaScriptへの変換を誰かが行う必要があります。1つめの方法は手動で変換をかけるものです。オンラインの変換ツールがありますので、ここにJSXをコピペすれば通常のJavaScriptに変換してもらえます。実際にやることはないでしょうが、一度このリンクを開いておいてください。2つめの方法は毎回動的に変換をかけるものです。src="app.js"></script>と書いておくと(type="text/jsx"に注目しましょう)、JSXで書かれたapp.jsをその場でJSXTransformerがJavaScriptに変換してくれます。これはお手軽なのですが、当然ながらパフォーマンス上の問題が生じますし、JSXTransformerは既にdeprecatedになっています。最後の方法は、何らかのツールでトランスパイル*1をかける方法です。Manager)というパッケージマネージャーがあります。多数の人々により様々なパッケージが提供されているわけですが、そのパッケージをダウンロード・インストールしてくれたり、その際に依存関係を解決してくれたり、また新しいコマンドをインストールしてくれたりする優れものです。npmで簡単に入ります。LinuxなどFedora系では入れるのが地味に面倒くさいので自分で調べてください。プロジェクト作成npmでは、まず最初にプロジェクトを作成する必要があります。initを実行すると、プロジェクト名などの基本情報を入力するように要求され*3、これが終わるとこのディレクトリはプロジェクトとして管理対象になります。管理対象と言っても、単に管理用ファイルpackage.jsonが新規作成されるだけです。パッケージ取得・インストールこれができたら次のコマンドでパッケージを取得・インストールすることができます。<パッケージ名>ここで--saveと書いているのは、package.jsonの中に「このプロジェクトが依存するパッケージ」としてインストールしたパッケージを記録しておくことを示します。開発時にのみ必要なパッケージをインストールする際は--save-devオプションを指定します。installでその中に記載されたパッケージを一括でダウンロード・インストールすることができます。インストールを行うと、プロジェクトのディレクトリ直下にnode_modulesディレクトリが作成され、ダウンロードしたファイル(多くの場合はJavaScriptのコード)が入ります。require("MODULE_NAME");などの文法で参照することができます。これについては後述します。インストールと同時にnode_modules/.bin/以下に実行可能ファイルが置かれるものもあります。これはプロジェクトごとにインストールされるものですが、プロジェクトによらず、OS全体で(グローバルに)利用したいこともあるでしょう。後述のgulpなどがそれにあたります。<パッケージ名>でインストールができます。OS全体に影響が及ぶのでsudoが必要なことがあります。Babel導入さて、上の方で試しに利用したオンライン変換ツールの名前はBabelとありました。そもそもBabelってなんでしょう?Babelの名前は、(おそらく)聖書のバベルの塔の記述、「全ての地は、同じ言葉と同じ言語を用いていた」から来ています。ES2017(ES7)といくつかのバージョンがあり、また正式採用前ながらも開発者コミュニティによく使われている文法もあり、さらにはJSXのような方言も存在します。そのサポート状況はブラウザによって異なります。先進的なバージョンの文法で書かれたJavaScriptはどれ一つとしてブラウザが対応していないことだって考えられますし、現時点ではJSXを理解できるブラウザは存在しません(これから先もないでしょう)。このようなJavaScriptを古いバージョンのJavaScriptに変換し、どのようなブラウザでも解釈できるようにしてくれるのがBabelです。「同じ言葉と同じ言語」が実現するわけですね。Babelはオンラインで使うこともできますが、普通はコマンドとして使いたいでしょう。そこでnpmを使います。このような流れで実行します。空のディレクトリを作り、そこに空のプロジェクトを作成します。init次にBabelとBabelのプリセットをインストールします。babel-preset-react変換が終わってしまえば稼働時には必要ないので--save-devを指定しています。これで準備は完了です。次のコマンドでJSXのファイルを読み込み、JavaScriptに変換して標準出力に吐き出します。document.getElementById('app'));先ほどオンラインで試したものと同じコードが出力されました。ES2016???上の方で出てきた「ES2015」「ES2016」について説明します。JavaScriptはECMAScriptという規格に沿った原語です。(ES2016)ES7とも呼ばれるというバージョンがあり、更新されるたびに便利な(あるいは複雑な)機能が追加されていっています。テンプレートリテラル(文字列の組み立て)などはもうES5の時代には戻れません。${name}.`);主要なブラウザが搭載しているJavaScriptエンジンはES2015に対応していますが、ES2016は新しすぎるためまったくと言っていいほど未対応です。gulp導入さて話を戻して、ここではgulpというツールを投入します。gulpとは「ビルドシステム」で、あらかじめ定義したタスクをまとめてコマンド一発で実行してくれるツールです。gulpがやってくれます。試しに使ってみるまず、グローバルでgulp-cliをインストールします。どこのディレクトリで実行しても構いません。gulp-cliこれでどこからでもgulpコマンドが実行できるようになりました。次に、プロジェクトのディレクトリに移動してgulpとgulpが利用するパッケージをインストールします。ここではJavaScriptのコードを圧縮するgulp-minifyを入れてみます。gulp-minifygulpは「あらかじめ定義したタスク」を自動で行うものだと言いました。この定義はgulpfile.jsというファイルで行います。プロジェクトディレクトリの直下にgulpfile.jsを作成し、以下のように書きます。["neko"]);ここではnekoという名前のタスクを定義していて、その内容はsrcディレクトリ以下の*.jsを対象にminify()して、結果をlibディレクトリに出力するというものになっています。タスク名が指定されなかった場合のdefaultタスクの内容としてはnekoを使ってね、ということも書いてあります。nekoと実行しても構いません)、libディレクトリ(存在しなければ自動的に作成されます)にオリジナルのapp.js、圧縮済みのapp-min.jsが出力されます。"+name+".");確かにコメントや空白が削除されて圧縮されています。Babelこれでgulpが何者かは分かりました。gulpからBabelを使えるようにしましょう。gulpが利用するパッケージをインストールします。babel-preset-es2015見知らぬ名前がたくさん出てきました。BabelのES2015用プリセット分かってしまえばどうと言うことはありませんね!*5gulpfile.jsの内容はこうなります。["neko"]);});さらにプロジェクトディレクトリの直下に.babelrcというファイルを新規作成します。これはBabelの動作内容を決める設定ファイルです。ReactのJSXとES2015を使いたいのでこのように書きます。"es2015"]}これで下準備が全て整いました。srcディレクトリにapp.jsを配置します。document.getElementById('app'));これでgulpを実行すると、libディレクトリに変換されたJavaScriptが出力されます。これを次のHTMLで読み込めば動作します。src="./lib/app.js"></script></body></html>ファイル監視gulpとだけ実行すると、gulpはタスクを1回だけ行って終了します。watchとすると、gulpはファイルの更新を監視し、更新されたらその場その場でタスクを繰り返し実行してくれます。手動でコマンドを実行する必要はなくなるのです。Browserify次に、上の項で唐突に出てきたBrowserifyの解説をします。UIのことを思い出してみましょう。UIはjQueryに依存している」と書いてあります。src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>のように書かないといけないのでした。このような依存関係は人間がドキュメントを読んだり書いたりして管理しないといけません。jQueryはグローバル変数$を利用するため、同じ変数を利用するライブラリとは同時に利用できません*6。これも利用者が気を配ってやる必要があります。Node.jsではどうやっているかこのような牧歌的な時代は終わりました。現代のJavaScriptではこんなのどかなことを言っていてはいけません。サーバーサイドJavaScript実行環境であるNode.jsには他モジュールのインポート機能があります。APIを使いたいのであれば、まずnpmを使ってaws-sdkパッケージをインストールします。aws-sdkプログラムコード中でaws-sdkをインポートするにはrequire()文を使います。EC2インスタンスを起動ブラウザでも同じことがしたいと誰もが思います。(現在の)ブラウザに許されるのは<script>タグでHTTPリクエストを発生させてソースコードを読み込むことだけ。このような仕事はブラウザの領分を超えています。そこでBrowserifyBrowserifyは、npmと組み合わせてこのインポート構文をブラウザ用JavaScriptにも持ち込むためのツールです。<パッケージ名>で必要なパッケージをインストールするJavaScriptのコードの中にrequire()文を書くBrowserifyを通すと、require()が消滅し、代わりに参照したパッケージが埋め込まれるこの結果、ユーザーは参照しているライブラリ(パッケージ)が全て結合された1つの大きな.jsファイルを得ます。名前空間の汚染がないような工夫も行われています。HH:mmとか)で出力したいというとき、整数のフォーマットが面倒でいつも頭を悩ませていました。従来はそのためのjQueryプラグインなどに頼っていたわけです。我々はもうjQueryと手を切ると決めたので、ここでnpmパッケージを探すとdateformatというものがあります。便利そうなので使わせてもらいましょう。インストールは簡単です。dateformatあとはrequire()で読み込むだけです。12:34"これをgulpでビルドすると、require()部分が消えてdateformatが取り込まれ、単体で動作するJavaScriptのソースコードが出てきます。react-dom.jsを直接CDNから読み込んでいました。これを統合してみましょう。react-domを追加します。react-dom次にapp.jsを修正します(上2行を追加します)。document.getElementById('app'));そしてgulpでこのapp.jsをビルドすると、生成されたlib/app.jsはライブラリを取り込んで700KBになりました*7。これならもうスクリプトは1個で済みます。src="./lib/app.js"></script></body></html>終わりにここまで準備してしまえば、その他のライブラリを導入するのも、別のトランスパイラを利用するのもぐっと障壁が低くなります。JavaScriptの開発環境は異様なほど流行廃りが速いのですが、なるべく便利なものをどんどん取り入れて快適に開発を進めていきたいものです。Gatewayで受けるこんにちは、AWS担当のwakです。APIとしてリニューアルしたとのことで、同僚が面白がって触っていたので説明してもらいました。聞くところによると、LINEのbotを友達登録したりメッセージを送ったりアンケートに答えたりすると、その内容がリアルタイムで自分のサーバーに送られてくるWebhookがあるそうです。WebhookはHTTPSのエンドポイントを要求します。Gateway+Lambda(Node.js)で受けることにしました。今回はその話を書きます。アプリケーションサーバーなど)に投げます。Gateway側で流量制御もできます。アプリケーションが直接インターネットに露出する必要がなくなるので気を遣う点が少なくなります。準備LambdaNode.jsで書きます。コードはこの記事の末尾にあります。先に作成しておいてください。MethodとたどってPOSTのエンドポイントを用意します。integration"のチェックをONにしてください。integrationがONなので、その他の細かい設定は不要です。Gatewayがアクセスを受け付けると、HTTPヘッダ、ボディ等がまとめてLambdaに渡されます。問題なければデプロイしてエンドポイントを確定させておきます。APIを探して設定画面を開きます。Secret」を取得し、Lambdaのコード中にコピペして更新しておきます*1。同じ画面の下の方にWebhookのエンドポイントを登録する場所があります。Gatewayのエンドポイントを書いて「VERIFY」ボタンを押してみましょう。Gateway経由でLambdaが実行され、ログが出力されるはずです。ログが出力されればこれで終わりです。あとはbotを友達登録したりチャットをしたりしてください。メッセージの検証さて、ちょっと別のことを考えます。LINE(メッセージを送信する側)の立場から見た場合、WebhookのエンドポイントはHTTPS限定ですから、登録したエンドポイントにメッセージを送信すれば確実に私に届くことは保証されています。なりすましに騙されて違う相手にメッセージが届いてしまうこと、送信経路でメッセージが盗聴・改竄を受ける可能性を気にする必要はありません*2。ところが私(メッセージを受ける側)から見た場合は話が変わります。誰かがLINEのサーバーを装って本物と同じフォーマットで偽のメッセージを送ってくるかもしれません。いった攻撃は正しく見破って破棄する必要があります。HMACでは、事前に共有した秘密鍵とメッセージを混ぜ合わせてハッシュを取り、MAC値と呼ばれる値を算出します。送信側はこのMAC値をメッセージに添えて送ります。受信側はメッセージの内容と秘密鍵*3から同じ手順でMAC値を算出し、添えられたMAC値と比較して、一致すればこのメッセージは本物であると判断します。メッセージに対応した正しいMAC値が分かるのは秘密鍵を知っている2人だけだからです。秘密鍵が分からないのにメッセージをでっち上げようとしてもうまくいきません。HMACの利点は秘密鍵そのものをメッセージに含める必要がないことで、つまりSSLを通さず平文でメッセージをやり取りすることも可能です(覗き見は避けられませんが、改竄は不可能だということになります)。従ってメッセージのMAC値(をBASE64エンコードした文字列)を算出します*4。${digest}`);});このdigestの値と、X-Line-Signatureヘッダの値とを比較すれば検証は終わりです。streamはいずれも標準の環境に含まれているため、特に複雑なことをする必要はありません。このコードではログを出力するだけですが、もちろんなんでも好きなことができます。});};*1:もちろん本当はDynamoDBとかに入れておきます*2:そのためのSSLなので*3:上述の通り、秘密鍵は事前にこっそり共有します。Gatewayでは文字列しか扱えません。Webフォームを用いているシステムも多々あると思います。弊社もWebフォームのシステムがあり、そこで普段やらないことをやりましたのでそれをまとめておきます。こんな処理を書くことはそうそう無いのですが何かの役に立つかもしれません。他システム(Linux/Apache)にアップロードするためのhtmlファイルをWebフォームを元に作成する。Formを使うことによりListView等にバインドできたり、編集が比較的楽というメリットがあります。コードも見やすいです。Formの結果であるため不要なタグを端折る必要があります。ここにいつも通りコードを書く。}}HttpContext.Current.Server.Executeで実行結果を受け取れますので、不要なタグを端折った後、ダウンロードさせています。Webフォームのドロップダウンコントロールでオートコンプリートをやろうというお話です。面倒だったのでまとめておきます。$(".autocomplete").autocompleteExtend();});参考先のコードを元に作成。入力値/選択値がリスト内の要素と完全一致するときのみポストバックさせます。動的に生成されるドロップダウンのスクロール指定等を行っています。最後の処理はautocompleteクラスを持つ要素に対してautocompleteExtendを呼び出すためのものです。</form></body></html>DropDownListコントロールにautocompleteクラスを指定しているのみです。}}実行すると入力すると一致する候補がきっちり表示されます。リストから選択すればSelectedIndexChangedイベントが発生します。(Select-String)の比較PowerShellこんにちは、PowerShellが好きなwakです。以前書いたこちらの記事をリライトします。\のエスケープっていらないの?はじめにWindowsにはgrepコマンドがないとはよく言われることですが、Windowsに標準で備わっているPowerShellにはgrepよりも高性能な検索コマンドレット、Select-Stringが実装されています。この記事はgrepとSelect-Stringとを比較し、慣れない人でもすぐに使えるようにすることを目的としています。「そもそもこのSelect-Stringコマンドをどうやって実行するの?」といったPowerShellの(超)基本的な使い方は本稿の末尾に記載してあります。(後述)以下、順に解説していきます。filename.txtPowerShellでこちらに相当する処理はこうなります。filename.txtSelect-Stringにはslsという省略形が用意されています。エイリアスですのでどちらを使ってもまったく同じ結果が得られます。filename.txt本稿では以降もSelect-Stringと表記しますが、もちろん実際に使うときにはslsで構いません。大文字・小文字を区別したい/区別したくないデフォルトでは大文字・小文字は区別されません。区別したい場合は-CaseSensitiveオプションを追加します。正規表現を使いたい/使いたくないパターンはデフォルトで正規表現とみなされます。正規表現として扱ってほしくない場合は-SimpleMatchオプションを追加します。パターンにマッチしない行を探したい-NotMatchオプションを使います。パターンにマッチした前後の行も出力したい-Contextオプションで行数を指定します。残念ながら前後別々に行数を指定することはできません。3文字エンコーディングを指定したい検索対象のファイルがShift-JISだと文字エンコーディングの自動判定ができないので、明示的に指定してあげなければいけません。これは-Encodingオプションを使います。oem-Encoding(gの後ろにスペース1個)と入力した後でTABキーを押せば指定可能な文字エンコーディングが順に表示されます。oemがShift-JISだと覚えておけば事足りるでしょう(UTF-8がデフォルトです)。複数のファイルから検索する場合ここまでは1件のファイルから検索を行うものでした。次は複数件のファイルを対象として検索を行う方法です。ワイルドカードを使いたいまず普通にワイルドカードが使えます。*.txt特定の複数のファイルを指定して検索したいワイルドカードではなく、ファイル名を書き並べたいならこうなります。カッコとダブルクオートが少々見づらいのですが我慢してください。"c:\data\text\filename2.txt")ディレクトリを再帰的にたどって検索したい次のどちらでも好きなものを選んでください。c:\data以下にある*.cs全てを検索対象としています。c:\data\*.csは、c:\data以下から*.csを全部探すという意味になります(1回このコマンドだけを実行してみるといいです)。ディレクトリ名を省略したらカレントディレクトリになります。特定の拡張子のファイルは除外したい-Excludeで除外できます。"pattern"検索対象のファイルを別のテキストファイルから与えたい1行に1件ファイル名(フルパス)が書いてあるテキストファイルfilelist.txtがあったとして、そこから検索をする場合です。}なお、カレントディレクトリ以下の全てのファイル名(フルパス)をファイルに書き出すにはこのように実行します。ワイルドカードの部分は必要に応じて*.txtなどと書き換えてください。UTF8出力の書式や出力先を変える標準の出力の書式では、ファイル名・行数・行の内容(行全体)が出力されます。いうと、この結果1行1行はそれぞれMicrosoft.PowerShell.Commands.MatchInfoクラスのインスタンスであり、このToString()メソッドがそのような書式の文字列を返すようになっているからです。Lineといったプロパティを持っていますから、欲しいものを好きなように並べて結果を出力することができます。結果だけを画面に出力したいファイル名はいらない場合です。~」と書き加える形でOKです。結果だけを画面に出力したいファイル名はいらない場合です。Line少し書式は面倒ですが、こちらの方を使うと色々と融通がききます。}このMatchesは.NETのSystem.Text.RegularExpressions.Matchクラスのインスタンスです。パターンに()を使っていればGroupsプロパティでさらに部分文字列を取り出せたりします。}.NETを使っている人にはお馴染みのSystem.String.Format()を使ってみました。`tは他言語の\tと同じタブ文字を意味します。PowerShellらしく書くなら次のどちらかになりそうです。}色々と試行錯誤したい検索結果をまず先に変数に格納しておけば毎回検索する手間が省けるので話が早くなります。filenameこれでまず検索結果が変数に入ります(画面には何も出ません)。}のように色々と試すこともできます。結果をファイルに書き出す検索結果は画面に出力するだけではなくファイルに書き出すこともできます。これについてはgrepと同じようにリダイレクトで吐き出すのが一番簡単でしょう。result.txt文字エンコーディングはUTF-16になります。ファイル名と書き加えるのではなく、さらにパイプをつなげてOut-Fileコマンドレットに渡します。UTF8ここで出力されるファイルはBOMありUTF-8という微妙なフォーマットになるのですが、これは諦めてください(少しコードを書けば解決するのですが)。起動まず、何はなくともPowerShellを立ち上げましょう。スタートメニューからPowerShellを探すエクスプローラーのアドレスバーに「powershell」と入力してエンターキーを押すエクスプローラーのメニューからPowerShellを起動するなんでもいいです。Select-Stringといったコマンドレットによって入力可能なオプションはあらかじめ決まっています。-まで入力してTABキーを連打すると、指定可能なオプションが列挙されます。-CaseSensitiveであれば、-cまで入力してTABキーを押せば一発で補完される、といった具合です。コマンドレット・オプションの大文字・小文字は区別されません。Select-StringをSELECT-STRINGやselect-stringと書いても問題ありません。\のエスケープっていらないの?PowerShellでは\文字は特別な意味を持ちません。AやBや.と同じ普通の文字です。したがって\のエスケープは必要ありません。正規表現を書くときにはこれが楽です。そのかわり、たとえば改行文字はn`、タブ文字は\t`と書くことになっています。バッククオートそのものを検索したいときはバッククオートを2つ連ねて書いてください。*1:デフォルトで区別なし*2:デフォルトで正規表現*3:grep単体では不可能。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。