君は心理学者なのか?

大学時代に心理学を専攻しなぜかプログラマになった、サイコ(心理学)プログラマかろてんの雑記。

json-serverが鬼のように便利で、しかも可愛かった

f:id:karoten512:20180512165110p:plain

いきさつ

APIのmockがほしかった。

今までexpressとかで実際にAPIをつくっていたのだが、

ちょっとめんどくさくなってきた。

何かいい方法がないかな〜と思ってたら「json-server」という良さげなものがあったので試してみた。

github.com

install

npm install -g json-server

jsonデータを用意

db.jsonというファイルを用意する。

{
  todos: [
    { id: 1, content: aaaa, done: false },
    { id: 2, content: bbb, done: true },
    { id: 3, content: ccc, done: true }
  ]
}

json-serverを起動

db.jsonというファイルを同ディレクトリ内に用意。

json-server --watch db.json

f:id:karoten512:20180512164253p:plain

絵文字がかわいい。

localhost:3000にアクセス

f:id:karoten512:20180512164428p:plain

こっちもかわいいかよ。

localhost:3000/todos/1 にアクセス

{
  "id": 1,
  "content": "aaaa",
  "done": false
}

しっかり返ってきてる。

まとめ

GETしか試していないが、

ドキュメントに

GET    /posts
GET    /posts/1
POST   /posts
PUT    /posts/1
PATCH  /posts/1
DELETE /posts/1

とあるのでいろいろ使えそう。

あとかわいい(重要)

【突然の沈黙】JavaScriptのobjectスプレッド演算子について

いきさつ

ソースコードを読んでいたら、

var arr = [1, 2, 3]
var arr2 = [4, 5, 6]
arr.push(...arr2)

とつぜん処理の中で沈黙(...)し始めた。

f:id:karoten512:20180511220526j:plain

気持ち悪かったので調べてみた。

ドキュメントを見てみる

スプレッド構文を使うと、関数呼び出しでは 0 個以上の引数として、 Array リテラルでは 0 個以上の要素として、 Object リテラルでは 0 個以上の key-value のペアとして、 Array や String などの iterable オブジェクトをその場で展開します。

うーん。

わかるようなわからんような。

実際に試してみよう。

...Array, ...Stringはどうなるのか

...Array だと

var arr = [1,2,3]
console.log(...arr) // 1 2 3

ばらばらになるイメージ?

...Stringだと

var str = 'hello world'
console.log(...str) // h e l l o   w o r l d

やはりばらばらになる。

ばらばらにしたものを、何かに渡してみる

関数呼出しに渡すその1

ためしに、...arrを3つの引数を受け取る関数に渡してみる。

var arr = [1, 2, 3]

function add(x, y, z) {
  return x + y + z
}

console.log(add(...arr)) // 6

なるほど。たしかに、

関数呼出しでは3つの引数として展開してくれている。

関数呼出しに渡すその2

この2つの配列をマージするケースを考えてみる。

var arr = [1,2,3]
var arr2 = [4,5,6]

arr.push(arr2)
console.log(arr) // [1, 2, 3, Array(3)]

普通にpushで書くとマージできない(当たり前だけど)

これじゃない。これがやりたいんじゃない。

ここで、

objectスプレッド演算子を使って展開した値を、

配列が持っている関数、pushに渡してみる。

var arr = [1,2,3]
var arr2 = [4,5,6]

arr.push(...arr2)
console.log(arr) // [1, 2, 3, 4, 5, 6]

おお。たしかに関数呼出し内で引数として展開されていることが確認できる。

なるほどねぇ。

配列に渡してみる

var str = 'hello world'
console.log([...str]) //  ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]

おー。確かに配列内で要素として展開されている。

これでsplitを使わなくても良くなるな。

まとめ

objectスプレッド演算子を使うと「ばらばらになる」

そのばらばらになったものを、関数に渡したり配列に渡したり、

Objectに渡したり(まだ試してないけど)することにより、

処理の記述が簡単になる。

Vue.jsにて、特定のroutingの時に後からComponentを読み込む〜ログイン後にコンポーネントを読み込みたいからLazy Loadしてみた〜

いきさつ

ログイン前はログインコンポーネントだけ、

ログイン後はアプリケーションに必要なコンポーネントを読み込みたい。

目的は、

ログイン前に読み込むJavaScriptソースコードの軽量化と、

それによるセキュリティリスクの減少。

やりかた

はじめ、こんな感じだったとします。

import Vue from 'vue'              
import Router from 'vue-router'

/** ログイン画面で読み込むコンポーネント */
import Login from '@/components/Login'

/** ログイン後に読み込みたい(Lazy Load)したいコンポーネント */ 
import Index from '@/components/Index'

Vue.use(Router)

export default new Router({        
  routes: [                        
    {
      path: '/login',
      name: 'Login',          
      component: Login             
    },
    {
      path: '/',
      name: 'index',
      component: Index
    }
  ]
})

これを、下のようにするだけです。

import Vue from 'vue'              
import Router from 'vue-router'

/** ログイン画面で読み込むコンポーネント */
import Login from '@/components/Login'

/** ログイン後に読み込みたい(Lazy Load)したいコンポーネント */ 
const Index = function () {
  return import('@/components/index')
}

// 後は同じ

importとreturn importの違いですが、

import Index from '@/components/Index'

とすると、Indexにはオブジェクトが入り、

const Index = function () {
  return import('@/components/index')
}

とすると、__webpack_requireという関数が入るようです。

ログイン後webpack_requireが実行され、その際にソースが読み込まれる感じ。

結果

f:id:karoten512:20180511004137g:plain

ログインボタンを押した後、

1.jsというファイルがあとから読み込まれている事が確認できます。

この1.jsにはindexコンポーネントの情報が入っていました。

Vue.jsでComponentを利用する〜templateのみ〜

f:id:karoten512:20180510000333p:plain

いきさつ

職場でVueを使うので勉強する必要がある。

とりあえず

vue-cliを使っても良いが、

きちんと理解したいので生で書くことにした。

ルートコンポーネント

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue TEST</title>
</head>
<body>

<div id="app">
  <my-component></my-component>
</div>

<script src="./vue.js"></script>
<script src="./app.js"></script>
</body>
</html>

ここでいうid="app"のdivで囲まれている部分がVueで管理される範囲。

今回はmy-componentタグで囲まれている部分をComponentとして、

Vueで管理してみる。

テンプレート情報だけをもつコンポーネントを作ってみる

// app.js
// コンポーネントの定義            
var mycomponent = {                
  template: '<div>hello</div>'     
};

// コンポーネントの登録
Vue.component('my-component', mycomponent);

// 今後生成されるすべてのvueインスタンスで使えるようになる
var app = new Vue({
  el: '#app'
});

component自体はタダのオブジェクト。

templateというkeyにcomponentのhtml構造をもたせることができる。

そして、

Vue.component('my-component', mycomponent);

でVue(のコンストラクタ)にcomponentを登録する。

この宣言をしておくと、

今後生成されるすべてのVueインスタンス内において、

mycomponentが使えるようになる。

まとめ

すごい単純。

メリットはhtml構造が使い回せるくらい。

Componentが増えたり処理が増えたりすると、Componentを単一ファイルで管理する

「単一ファイルコンポーネント」ということになってくる。

イスラーム過激派のハッカーが知人のサーバをハッキング。マルウェアが6000個検出された話

f:id:karoten512:20180506181832p:plain

いきさつ

知人のサイト(WordPress)が見れなくなったということで、

とりあえずsshでログインしてみた。

とりあえず調査

探し方としてはかなり荒っぽいけど、とりあえず

phpファイルのうち、evalを含むファイルを検索した。

find . -type f -name "*.php" | xargs grep 'eval'

あった。

あったというか滅茶苦茶あった。

カウントしてみる。

find . -type f -name "*.php" | xargs grep 'eval' | wc -l
6000

えぇー。

いったん応急処置

あまりサイトが見られない時間が長いのはSEO的にヤバイ(メディア系なので)。

いったんマルウェアを削除して再アップし、

その後にログ調査などして根本原因を突き止めることにした。

マルウェア削除 軌跡

ファイルを調べてみると

3月10日に生成されているファイルがほとんどだった。

(念のため日付はぼかしてあります)

そこをハッキングされた日として、

一旦一週間前の3月3日以降に生成された怪しいファイルを、

どんどん消していくことにした。

find . -type f -name "*.php" -newermt "2018-03-03"

を元に、

怪しい文字列を含むファイルを検出、中を確認しながら順番に削除していく。

(すごい古典的な方法だから絶対もっといい方法があるはず)

どんなファイルがあったか

以下の3つに分けられた。

webshell系

f:id:karoten512:20180506183356p:plain

webshellってのはざっくりいうと、

webブラウザからシェルを使えるようにするやつ。

ファイルの転送、実行、編集、削除、

シェルコマンドの実行など、シェルでできそうなものならなんでもできる感じ。

DBにアクセスしたりすることもできる。

これが置かれたらサーバに対してだいたいなんでもできる。

非常に厄介。

これが1000個くらい。

なぜか3種類くらいのwebshellが置かれていた。そんなにいる?

メーラー

サーバからスパムメールを送ることができるツール。

leafmailerというphpで作られた有名なツールが置かれていた。

これが3000個くらい。

自己誇示系

Hacked by ***

みたいに、自分のハンドルネーム的なファイルを書き残している。

これが2000個くらい。

とりあえず怪しいファイルは全部消した

結局3月10日以降に作られたファイルは全部マルウェア系だった。

攻撃者のプロファイル

ファイル名や、Hacked by *** から、攻撃者のプロファイルが何となく想像付いた。

攻撃者はおそらく、

イスラーム過激派

か、

それを騙った愉快犯っぽい。

ファイル名で検索するとそれっぽい写真がいっぱい出てくる。

どちらにしても迷惑だな。手当たり次第かよ。

脆弱性を突き止めるために

現在、ハッカーさんがアクセスログを残してくれているっぽいので解析中。

ログ残してくれてるあたり、あまりプロの仕事ではないんだろうなぁ。

優秀な人は、ログを改ざんしたり削除したりしていくらしいけど。。。

まとめ

ハッキングされると後が大変。。。やめてほしい。。

ファイルのタイムスタンプを保持したまま、scpコマンドで転送する

f:id:karoten512:20180506162850j:plain

いきさつ

サーバからファイルをダウンロードした後、

日付情報を用いてファイル処理をする必要があった。

コマンド

scpコマンドにpオプションを付けるだけ。

scp -rp remote_host:remote_dir local_dir

ちなみに

ファイル転送時に新しく作られるディレクトリについては、

どうしても転送時のタイムスタンプになるっぽい。

【OSSリーディング企画】BootstrapのJavaScriptを読み解く【その1】

f:id:karoten512:20180504205854p:plain

いきさつ

Bootstrap、すごい便利。

htmlタグさえドキュメントどおりにおけば*1

ルーセルは動くわモーダルは開くわアラートは出るわ、、、

f:id:karoten512:20180504211100j:plain

いつも本当にお世話になっております。

ただ、、、ただね、

なんで動くのか」について全然考えたことがなかったんですよ。

細かいところを調整しようと思った時に、

中がどうなっているのか分かっていないので、

手が完全に止まってしまう。。。

これじゃあ「ライブラリを使っている」のではなく、

「ライブラリに使われている」。そんな気がしてならない。。。

というわけで、OSSリーディングを始めました。

対象OSS

今回はBootstrapのモーダル周りについて読んでいきます。

読むファイルはこれ。

github.com

すでにビルドされている生のJavaScript

どうせならJavaScriptも軽く復習したい。

そういう思いもあります。

OSSを読むにあたって大切なこと

「全部は読まない。読みたいとこだけ」

なんだか懐かしい響きですね。

moto-neta.com

OSSを、はじめから全部読もうと思ってはいけません。

なんせOSS(今回はBootstrap)は、

「1000人以上の人が」

「何年もかけて」

開発をしているライブラリです。

はじめから全部読むのはツライツライ。

今回のゴール

何もしていないのに(JS書いていないのに)なんでボタンを押したらモーダルが開くのか

に絞って読んでいきます。

モーダルを開く処理までは読みません。

「ボタンを押したら」という部分に着目し、

ボタンに対してclickイベントを登録している部分を読み解きます。

また、その途中で即時関数が使われているので、即時関数についても簡単に触れます。

読んでいきます

Modalモジュールが宣言されている部分

/**
 * --------------------------------------------------------------------------
 * Bootstrap (v4.1.1): modal.js
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * --------------------------------------------------------------------------
 */

var Modal = function ($$$1) {
   // いろいろな処理
}($);

だいたい1930行あたりにModalモジュール(モジュールという言い方が正しいのかどうかは微妙)が宣言されていますね。

Bootstrapでは様々な機能が使えますが、

これらはみなモジュールとして提供されています。

すごい乱暴に書くとこんな感じ。

var Modal = function ($$$1) {
   // いろいろな処理
}($);

var Carousel = function ($$$1) {
   // いろいろな処理
}($);

var Alert = function ($$$1) {
   // いろいろな処理
}($);

exports.Alert = Alert;
exports.Carousel = Carousel;
exports.Modal = Modal;
...

各モジュールで使われる変数は関数の中で定義され、カプセル化されています。

それにより、他のモジュールで使われている変数とぶつかったりすることはありません。

かしこい(小並感)。

exportsの意味について

そして、

exports.Alert = Alert;
exports.Carousel = Carousel;
exports.Modal = Modal;

exportsにはwindow.bootstrapオブジェクトが入っているよ。*2

つまり、もっと分かりやすく書くとこんな感じ。

window.bootstrap.Alert = Alert;
window.bootstrap.Carousel = Carousel;
window.bootstrap.Modal = Modal;

なので、コンソール上でwindow.bootstrapすると、

これらのモジュール(正確にはコンストラクタ)にアクセスすることができるよ。

f:id:karoten512:20180504213318p:plain

Modal用のボタンにクリックイベントをバインドしている部分

さて、Modalを開くためのボタンのhtmlを確認してみるよ。

<button type="button" data-toggle="modal" data-target="#exampleModal">
  Launch demo modal
</button>

これだけでいいらしいよ。ふざけてるね!

重要なのは、

data-toggle="modal"

という部分。

これを目印にして、

このdata属性を持っている要素にclickイベントをバインドしているよ。

こんな感じ!

// 2500行あたり
$$$1(document).on('click', '[data-toggle="modal"]', function (event) {
  // クリックした時に起こるイベント
}

え?

でもなんで勝手にclickイベントがバインドされるかって?

それは、この処理が即時関数の中で実行されているからだよ!

var Modal = function ($$$1) {
   // 即時関数の中
  $$$1(document).on('click', '[data-toggle="modal"]', function (event) {
    // クリックした時に起こるイベント
  }
}($);

一度JavaScriptが読み込まれると即時関数は勝手に実行されるので、

html上にdata-toggle="modal"さえ書いておけば、

勝手にclickイベントがバインドされるんだね!

即時関数の使い所

「一度しか実行されない処理」を即時関数で書くことが多いよ。

今回のように、

「特定の要素に対してイベントリスナを登録」

という処理は1度だけの実行でいいから、よく使われるよ。

即時関数のメリット

即時関数で処理を包むことにより、

変数のスコープが即時関数内に限定されるので、

グローバルスコープを汚さないよ!

巷のライブラリでも即時関数はよく見るよ。みてみてね!

まとめ

というわけで今回は、

モーダルを開くためのボタンに対してclickイベントが登録されている部分を確認してみました。

data-toggle='modal'さえ持っていればよいので、

ボタンだろうがlistだろうがdivだろうがなんでもモーダルが開けそうですね。

BootstrapのJavaScriptは、

定数がきちんと宣言されていたり、

jQueryからモーダルを操作できるようなAPIを提供していたり、

複数のモーダルを開くことができるような実装の仕方をしていたりと、

すごく勉強になる部分が多いので、ひきつづき読んできたいと思います。

*1:JavaScript書かなくてよいことも多い

*2:気になる人は1行目から読んでみよう。Boostrapがブラウザ上で実行される場合、exportsにはwindow.bootstrapオブジェクトが代入されているはずだ