くりーむわーかー

プログラムとか。作ってて ・試しててハマった事など。誰かのお役に立てば幸いかと。 その他、いろいろエトセトラ。。。

2020年07月

10億人が笑うSVGからナゼか正規表現の話

Billion laughs攻撃っていうのがある。

XMLで参照を多重に定義して、メモリを食いつぶさせてPCとかアプリを固まらさせるやつ。

で、これってSVGでも可能だったんですね。

下の画像をFireFoxで見るとFireFoxのタブが固まる。(Chromeは大丈夫だった)

https://github.com/cirosantilli/web/blob/master/svg-billion-laughs.svg

上の画像をDLして、例えばパワーポイントとかに画像挿入しようとするとパワポも固まる。


上の画像のソースを見ればわかりますが、この程度の参照の組み方だけで、

組み合わせ爆発でヤバイ事になるという訳なんですが、

参照をネストさせるようなものはやっぱり考え物って事ですね。

正規表現なんかも、例えば

(a|b|c)(e|d|f)

みたいに組み合わせで色々やるとエライこっちゃになるパターンがあったと思う。

↑だけじゃ再現させられなかったんですが、昔どこかのコードで見たんだよなー。

組み合わせ爆発って怖いですね。結構意識せずにやっちゃいそうな気もする。


正規表現でいうとMSDNの正規表現のベストプラクティスのページがすごく面白かった。

長さが 5 文字を超えると、文字列の文字が 1 文字増えるたびに処理時間が約 2 倍に増加します。 つまり、有効に近い文字列の長さが 28 文字になると処理に 1 時間以上かかり、33 文字になるとほぼ 1 日かかることになります。

確かに正規表現作ってる時って、正しい文字列ばっかり考慮してるきらいがありますよね。

「*」とか「+」とかのネストとかもやばそう。

正規表現だと楽ーとか早いとかいう話は良く見聞きしますが、

やっぱり一概にそうも言えないですよね。

MariaDBのクエリログ

完全にメモ。ささっと確認したい時にいっつも忘れる。

SET GLOBAL general_log=1;
SET GLOBAL log_output='TABLE';
SELECT * FROM mysql.general_log\G

戻すときは0にセット。

FILEの場合は多分この辺り。

/var/log/mysql/mariadb.log

公式DOC

AWSにVMイメージをインポートしてインスタンス作る(WindowsServer 2003)

WindowsServer2003という古のOSがありまして、

そのVMイメージをAWSで動かせるのかというお試し。

結果から言うととりあえず動かせはした。


VMインポートの手順は大まかに下記の流れ。

1. VMをエクスポートしておく
2. S3にバケット用意(既存を使うならそれはそれで
3. IAMで作業用のユーザ作っておく
4. aws cliをインストールしてconfig
5. aws cliでロールとか作る
6. aws cliでS3にVMイメージをアップロード
7. aws cliでアップロードしたイメージをAMIに変換
8. AMIからインスタンスを起動

基本的に公式のココのページ通りやっていけば大丈夫。


1. VMをエクスポート

色々やり方あると思うのですが、基本的にこのページのやり方でやらないとだめ。

2. S3にバケット用意

これはS3のサービス開けば問題ないでしょう。

3. IAMで作業用のユーザ作っておく

既存のユーザでも問題ないですが、後続のaws cliでアクセスキーとシークレットアクセスキーを使うのでそれが分からない場合は作るしかないかなと。

色々面倒そうなので、adminグループのユーザ作ってやった。。。

4. aws cliをインストールてconfig

公式のインストールのページから。windowsでやるのでwindows用をDLしてインストール。v2でやる。

インストールできたら、コンフィグ。

aws configure

> AWS Access Key ID [None]: *******
> AWS Secret Access Key [None]: *******
> Default region name [None]: ap-northeast-1
> Default output format [None]: json

東京リージョンは ap-northeast-1
5. aws cliでロールとか作る

公式のドキュメント

  • trust-policy.jsonを作成
{
   "Version": "2012-10-17",
   "Statement": [
      {
         "Effect": "Allow",
         "Principal": { "Service": "vmie.amazonaws.com" },
         "Action": "sts:AssumeRole",
         "Condition": {
            "StringEquals":{
               "sts:Externalid": "vmimport"
            }
         }
      }
   ]
}
  • JSON作ったら vmimport っていう名前で作成
aws iam create-role --role-name vmimport --assume-role-policy-document "file://C:\work\trust-policy.json"
  • role-policy.json を作る
{
    "Version":"2012-10-17",
    "Statement":[
       {
          "Effect": "Allow",
          "Action": [
             "s3:GetBucketLocation",
             "s3:GetObject",
             "s3:ListBucket" 
          ],
          "Resource": [
             "arn:aws:s3:::ines-wr-tempdata",
             "arn:aws:s3:::ines-wr-tempdata/*"
          ]
       },
       {
          "Effect": "Allow",
          "Action": [
             "s3:GetBucketLocation",
             "s3:GetObject",
             "s3:ListBucket",
             "s3:PutObject",
             "s3:GetBucketAcl"
          ],
          "Resource": [
             "arn:aws:s3:::ines-wr-tempdata",
             "arn:aws:s3:::ines-wr-tempdata/*"
          ]
       },
       {
          "Effect": "Allow",
          "Action": [
             "ec2:ModifySnapshotAttribute",
             "ec2:CopySnapshot",
             "ec2:RegisterImage",
             "ec2:Describe*"
          ],
          "Resource": "*"
       }
    ]
 }
  • JSON作ったら vmimport に反映
aws iam put-role-policy --role-name vmimport --policy-name vmimport --policy-document "file://C:\work\role-policy.json"

※ローカルのファイルパスはフルパスで作ったJSONファイルを指定。

6. aws cliでS3にVMイメージをアップロード

下記の感じ。

aws s3 cp "C:\work\hogehoge.disk1.vmdk" s3://work/vm

vmdkだけあればよいっぽいけどとりあえずエクスポートで作られたファイルは全部上げた。

7. aws cliでアップロードしたイメージをAMIに変換
  • containers.json ファイルを作る
[
  {
    "Description": "Disk01",
    "Format": "vmdk",
    "UserBucket": {
        "S3Bucket": "work",
        "S3Key": "vm/hogehoge.disk1.vmdk"
    }
  },
  {
    "Description": "Disk02",
    "Format": "vmdk",
    "UserBucket": {
        "S3Bucket": "work",
        "S3Key": "vm/hogehoge.disk2.vmdk"
    }
  },
  {
    "Description": "Disk03",
    "Format": "vmdk",
    "UserBucket": {
        "S3Bucket": "work",
        "S3Key": "vm/hogehoge.disk3.vmdk"
    }
  }
]

vmdk複数ある場合は↑の感じ。

  • インポートする
aws ec2 import-image --description "HogeTestVM" --disk-containers "file://C:\work\containers.json"
8. AMIからインスタンスを起動

インポートが終わったら、AMIにイメージが出来てるのでそれを選んで起動すればOK。


ここまでで、大体動くようにはなってると思う。

ただ、本当はここから下記の設定をした方がよいっぽい。

インスタンス上げてみてみると、EC2Configの方は勝手にインストールされてた。

ただ、ENAとNVMe のドライバーのインストールはWindowsServer2003では不可能っぽい。

何でかって言うとPowerShellが2.0しか入れられないから。

がんばれば3.0以降も入るのかな?どこかで2003は2.0しか動作しないような事を見た記憶ががが...

ENAとNVMeはあきらめましたとさ。

でも、とりあえず動いてはいる。

顧客向け用の環境としてはあり得ないんだけど、開発用でどうしても一時的に必要な状況はあるので、何かの参考に置いておきます。

windows server 2003をAWS上に復元するのとか検索しても全然出てこなかった。

まーやる人なんかいないですよね。。。

AWSのLinuxサーバをデスクトップ化してローカルのWindowsからRDPで接続

まとめ。AWS側はCentOS7。

# SELinux切る(とりあえず)
sudo setenforce 0
sudo vi /etc/selinux/config
  SELINUX=disabled

#ファイヤーウォール切る(とりあえず)
sudo systemctl stop firewalld
sudo systemctl disable firewalld

# デスクトップ環境
sudo yum groupinstall graphical-server-environment -y

# VNCサーバー
sudo yum install tigervnc-server -y

# EPELリポジトリを有効化
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm -y

# xrdp
sudo yum install xrdp -y

# xrdpの起動とサービス化
sudo systemctl start xrdp
sudo systemctl enable xrdp

# パスワード変更(RDP接続時は必須っぽ)
sudo passwd centos

あとは、RDPのポート(3389)をIPフィルタで外してあげればローカルのリモートデスクトップでつなげる。

パスワード変更しても通常のSSHでの接続でパスワード求められるわけじゃない。

AWSのWindowsサーバを日本語化する

デフォでローカルが英語なので日本語化したい。

前は設定から日本語選べば自動的に言語パックDLして適用してくれたみたいなのですが、

最近はやってくれない模様。そのうち治るのかしら?


①インターネットオプションで信頼済みサイトに下記

https://*.microsoft.com

➁IEのURLに下記を入れて直DL


https://software-download.microsoft.com/download/pr/17763.1.180914-1434.rs5_release_SERVERLANGPACKDVD_OEM_MULTI.iso

➂上記をダブルクリックで「Microsoft-Windows-Server-Language-Pack_x64_ja-jp.cab」がある事を確認。

④Windowsキー + Rでファイルを指定して実行:langpacks

⑤で、上記のja-jp.cabを選択してインストール

⑥ウィンドウズキー⇒設定⇒言語

⑦言語でAddからjapaneseを追加

⑧あとはリージョンとか適当に設定。

20200716追記

⑨コンパネから行く地域も日本にしないとダメでした...


言語パックのDLってMicrosoftのページに無いのかしら。

見つけられなかったのですが...

NuxtのテストをCypressでCoverage付でやる

Nuxtのテストがつらい。vue-test-util使って書くのがツライ。

簡単なコンポーネントなら良いと思うのですが、ガチでテスト書こうとすると

mountとか色々上手く動かなかったり、都度アレコレ調べて、「苦肉の策」みたいなコードを

書かないといけないのがつらすぎる。

皆アレでやってるんですかね?書けなくはないんだけど、つらすぎじゃないですか?


という事で、CypressでE2E的に単体テストをやりたくなった話。

Cypressで単体テストをやろうとすると問題になるのが、カバレッジ。

カバレッジが取れないので無理だよなーとか思ってたら、ちゃんと出来るっぽいので組み込んでみた。

最終系は下記に上げてます。

https://github.com/n79s/nuxt-cypress-coverage-sample

参考


まず必要なパッケージのインストール。

npm install --save-dev @cypress/code-coverage nyc istanbul-lib-coverage babel-plugin-istanbul cypress

そしたら一回cypressを動かしてテンプレのファイルとか作ってもらう。

npx cypress open

あとは設定。

  • ./nuxt.config.js
  build: {
    babel: {
      plugins: [['babel-plugin-istanbul']],
    },
  },
  • ./.babelrc
{
  "env": {
    "test": {
      "plugins": ["istanbul"],
      "presets": [
        [
          "@babel/preset-env",
          {
            "targets": {
              "node": "current"
            }
          }
        ]
      ]
    }
  }
}
  • ./nyc.config.js
module.exports = {
  all: true,
  extension: ['.js', '.vue'],
  exclude: ['**/*.{spec,test}.{js,ts}'],
  include: [
    'pages/**/*.{vue,ts}',
    'layouts/**/*.{vue,ts}',
    'components/**/*.{vue,ts}',
    'module/**/*.js',
    'mixin/**/*.js',
    'store/**/*.js',
  ],
}
  • ./cypress/support/index.js
import './commands'
import '@cypress/code-coverage/support'
./cypress/plugins/index.js
module.exports = (on, config) => {
  require('@cypress/code-coverage/task')(on, config)
  on('file:preprocessor', require('@cypress/code-coverage/use-babelrc'))
  return config
}


あとおまけで、vscodeでcypressのインテリジェンス効くようにする。

  • ./jsconfig.json
{
  "include": ["./node_modules/cypress", "cypress/**/*.js"]
}


あとは適当にコンポーネントとか作って実行すると下記の感じでカバレッジが取れるようになる。

カバレッジはデフォだと「coverage/lcov-report/index.html」

sample-cov


どうやってカバレッジ取ってるのかと思ったら、

カバレッジ用のオブジェクト(パスが通ったら該当行のカウントアップするやつ)を

「window.__coverage__」に丸ごと登録してブラウザ側に渡して、ブラウザで実行される時に、

実行してる行のカウントアップをしてるっぽい。

なるほどなー。


で、これだとブラウザのUIを通してしか実行が出来ない。

例えば、Vuexの値を直で見たい場合とかComponentのmethods何かを直で動かしたい場合にどうするかというところ。

まずVuex。

Nuxtは自身をwindow.$nuxtに登録しているのでそれを下記の感じで取得すれば直で呼べる。

const getStore = () => cy.window().its('$nuxt.$store')

    getStore().its('state.vcounter').should('equal', 6)//値を直で見る
    getStore().then((store) => {
      store.dispatch('setCounter', 10)//アクション呼ぶ
      getStore().its('state.vcounter').should('equal', 10)
      cy.wrap(store.getters.vcounter).should('equal', 10)
    })

Componentは一工夫。というかかなり無茶が必要。

ブラウザ側からやる場合、どうしてもコンポーネントの参照をどこかに持たないと無理。

なので、コンポーネントがmountされる時に、自身をwindowに登録するようにpluginでグローバルミックスインを置いておく。

import Vue from 'vue'

if (window.Cypress) {
  window.$allComponents = []

  Vue.mixin({
    mounted() {
      if (this.$vnode) {
        if (String(this.$vnode.tag).includes('pages'))
          window.$allComponents.push(this)
      }
    },
  })
}

通常は入れたくないので、Cypressで動いてる時だけやるようにする。

全コンポーネントでやってもいいと思うのですが、自分はページコンポーネントだけでやってる。

ページコンポーネントの$childrenにそのほかのコンポーネントは入ってるのでそれでいいかなと。

そしたらこんな感じで使う。

const getPageComponent = (pagepath) =>
  cy
    .window()
    .its('$allComponents')
    .then((compos) => {
      for (const x of compos) {
        if (String(x.$vnode.tag).includes(pagepath)) {
          return x
        }
      }
    })

describe('Counter Test Component Direct', () => {
  it('ClickCounter', () => {
    cy.visit('http://localhost:3000')
    cy.get('.button--grey').click()
    cy.url().should('include', '/sample02')

    getPageComponent('pages/sample02').then((target) => {
      cy.wrap(target.$children).its(0).invoke('handleClick')//methods の関数を直呼び
      cy.wrap(target.$children).its(0).its('vcounter').should('equal', 2)//data()を直参照
      cy.wrap(target.$children).its(0).invoke('handleClick')
      cy.wrap(target.$children).its(0).invoke('handleClick')
      cy.wrap(target.$children).its(0).its('vcounter').should('equal', 6)
    })
  })
})


ただ、これだとVue側の警告が裏で上がってるので他に良いやり方無いかなー。

問合せ