読者です 読者をやめる 読者になる 読者になる

謎言語使いの徒然

適当に気になった技術や言語を流すブログ。

Playframework 2.5 で足りてなさそうなセキュリティヘッダ設定を追加する

Playframework 勉強 日記 Scala

セキュリティヘッダなんて、ヘッダに組み込むだけのものなので、ザクッと。

package filters

import javax.inject.{Inject, Singleton}

import akka.stream.Materializer
import play.api.Configuration
import play.api.mvc.{Filter, RequestHeader, Result}

import scala.concurrent.{ExecutionContext, Future}

/**
 * Add custom security header responds.
 * Created by azalea on 2016/08/29.
 */
@Singleton
class SecureHeaderFilter @Inject() (
  implicit override val mat: Materializer,
  exec: ExecutionContext,
  conf: Configuration
) extends Filter {

  private def prefix(k: String) = s"play.filters.$k"

  val XFrameOptions = conf.getString(prefix("frameOptions"))
  val xssProtection = conf.getString(prefix("xssProtection"))
  val contentTypeOptions = conf.getString(prefix("contentTypeOptions"))
  val permittedCrossDomainPolicies = conf.getString(prefix("permittedCrossDomainPolicies"))
  val contentSecurityPolicy = conf.getString(prefix("contentSecurityPolicy"))
  val strictTransport = conf.getString(prefix("strictTransport"))
  val downloadOptions = conf.getString(prefix("downloadOptions"))
  val cacheControl = conf.getString(prefix("cacheControl"))
  val pragma = conf.getString(prefix("pragma"))
  val expires = conf.getString(prefix("expires"))

  val headers = Seq(
    XFrameOptions.map(v => "X-Frame-Options" -> v),
    xssProtection.map(v => "X-XSS-Protection" -> v),
    contentTypeOptions.map(v => "X-XSS-Protection" -> v),
    contentSecurityPolicy.map(v => "Content-Security-Policy" -> v),
    permittedCrossDomainPolicies.map(v => "X-Permitted-Cross-Domain-Policies" -> v),
    strictTransport.map(v => "Strict-Transport-Security" -> v),
    downloadOptions.map(v => "X-Download-Options" -> v),
    cacheControl.map(v => "Cache-Control" -> v),
    pragma.map(v => "pragma" -> v),
    expires.map(v => "expires" -> v)
  ).flatten

  /**
   * add secure headers.
   *
   * @param nextFilter next filter function.
   * @param rh         request header.
   * @return           header annotated result.
   */
  override def apply(nextFilter: (RequestHeader) => Future[Result])(rh: RequestHeader): Future[Result] = {
    nextFilter(rh).map(res => res.withHeaders(headers:_*))
  }
}

設定ファイルはこんな感じ。もともとあった Play のセキュリティ設定に追記する形。

play.filters {
  headers {
    # The X-Frame-Options header. If null, the header is not set.
    frameOptions = "SAMEORIGIN"

    # The X-XSS-Protection header. If null, the header is not set.
    xssProtection = "1; mode=block"

    # The X-Content-Type-Options header. If null, the header is not set.
    contentTypeOptions = "nosniff"

    # The X-Permitted-Cross-Domain-Policies header. If null, the header is not set.
    permittedCrossDomainPolicies = "master-only"

    # The Content-Security-Policy header. If null, the header is not set.
    contentSecurityPolicy = "default-src 'self'"

    # My custom security headers.
    # The Strict-Transport-Security header.
    #strictTransport = "max-age=31536000; includeSubDomains"

    # The X-Download-Options header.
    #downloadOptions = "noopen"

    # The Cache-Control header.
    cacheControl = "no-cache, no-store, must-revalidate"

    # The pragma header. for old cache server.
    pragma = "no-cache"

    # The expires header.
    expires = "-1"
  }

上から順に説明すると、

  • X-Frame-Options
    画面内フレームコンテンツの制限。 DENY:フレームの全面禁止、SAMEORIGIN:同じドメインコンテンツは許可、ALLOW-FROM origin_uri 指定URLのコンテンツはフレーム表示許可
    意図しない、詐欺サイト表示対策など。
  • X-XSS-Protection
    ブラウザの XSS 保護機能を有効化する。0: で保護を無効化。1で有効化
  • X-Content-Type-Options
    サーバが返してきたヘッダに従ってファイルを処理する。
    特に IE なんかだと、ファイルの中身を確認して勝手に対応アプリを開く悪癖があって、拡張子を js にした JavaScript なんかを仕込む攻撃の対策
  • X-Permitted-Cross-Domain-Policies
    crossdomain.xml の置き換え。JavaScript で複数のサーバと通信する場合の、許可証設定。
  • Content-Security-Policy
    HTML,JavaScript,音声,画像などなど、アクセスしていいドメインの制限。 default-src 'self' は同一ドメイン以外からの一切のデータ取得禁止。
  • Strict-Transport-Security
    このURLは HTTPS でアクセスセーよというお達し。中身はお察し
  • X-Download-Options
    ダウンロードしたファイルは、HTML 内での img タグとかを除いて、勝手に開くんじゃねーよ指定。
    アップロード・ダウンロードをするシステムでは有用
  • Cache-Control
    プロクシとか、キャッシュサーバとかに「キャッシュしてんじゃねーよ」と通知。
    個人情報入りのページをキャッシュされたら個人情報漏洩になるでしょ〜が!
    no-cache: キャッシュすんじゃねーぞ。有効性確認しなけりゃキャッシュ使うんじゃねーぞ
    no-store: リクエスト・レスポンスの一部分をローカルストレージに保存するんじゃない must-revalidate: 毎回サーバに確認しろ
  • pragma
    Cache-Control の no-cache と同様。古いキャッシュサーバ向け。
  • expires
    キャッシュコンテンツの有効期限。-1 では常に「そのキャッシュは無効」

Scala 関数型デザイン&プログラミング:Exercize3.16-3.23

日記 Scala 勉強

Scala 関数型デザイン&プログラミング:Exercize3.2 - 3.13 - 謎言語使いの徒然 の続き。

Exercise 3.16

各要素に +1 したリストを返す関数を作れ。

なんか仕様的に map 関数に似てるなーと思った。
とりあえず フォイ

  def map[A, B](as: List[A], func: A => B): List[B] =
    foldRight(as, Nil:List[B])((a, b) => Cons(func(a), b))

  def increment(as: List[Int]): List[Int] = map[Int, Int](as, v => v + 1)

  /*  printRec(List.increment(List(1, 2, 3, 4))) */

Exercise 3.17

List[Double] を List[String] にする関数を作りなさい。

はいはい mapmap

  def toStringList[A](as: List[A]): List[String] = map[A, String](as, _.toString)

しかしこの map 型指定しないとコンパイルコケるのはダサいな。

Exercise 3.18

下記シグネチャで map 作れ def map[A, B](as: List[A], func: A => B): List[B]

上記 map のシグネチャだけ変更。
何か型推論がいい仕事始めて、「map[A, String](as, _.toString)」が「map(as)( _.toString)」になった。

引数が一つであることを(curry にでもして)保証すると精度でも上がるのかね?

Exercise 3.19

与えられた条件を満たされるまでリストから要素を削除する filter 関数を記述せよ。 def filter[A](as: List[A])(f: A => Boolean): List[A]

まぁ foldRight あれば余裕な

  def filter[A](as: List[A])(f: A => Boolean): List[A] =
    foldRight(as, Nil: List[A])((a, b) => if (f(a)) Cons(a, b) else b)
  /* printRec(List.filter(List(1,2,3,4,5,6,7,8,9))(_ % 2 == 0)) */

Exercise3.20

map と似た動きをする関数、flatMap を作れ。シグネチャは下記の通り。 def flatMap[A,B](as: List[A])(f: A => List[B]): List[B] flatMap(List(1, 2, 3))(i => List(i, i)) と書いたら、List(1, 1, 2, 2, 3, 3) を返せ。

Scala 標準の flatMap ほど高機能ではないか…?

  def flatMap[A,B](as: List[A])(f: A => List[B]): List[B] = concat(map(as)(f))
  /* printRec(List.flatMap(List(1, 2, 3))(a => List(a, a))) */

Exercise3.21

flatMap を使って filter を実装せよ。

何だ? f(x)==false の時 Nil にでもするのか?

  def filterViaFlatMap[A](as: List[A])(f: A => Boolean): List[A] =
    flatMap(as)(a => if(f(a)) List(a) else Nil: List[A])

  /* printRec(List.filterViaFlatMap(List(1,2,3,4,5))(_ % 2 == 0)) */

何だろう…効率的な実装に見えない。

Exercise3.22

同数二つの List[Int] を受け取って、対応する要素同士で足し算する関数を作れ。

  def addPairwise(list: List[Int], list1: List[Int]): List[Int] = {
    def addPairwise(a: List[Int], b: List[Int], sum: List[Int]): List[Int] = {
      (a, b) match {
        case (Nil, _) => sum
        case (_, Nil) => sum
        case (Cons(ah, at), Cons(bh, bt)) => addPairwise(at, bt, Cons(ah + bh, sum))
      }
    }

    reverse(addPairwise(list, list1, Nil: List[Int]))
  }
  /* printRec(List.addPairwise(List(1,2,3), List(1,2,3))) */

こうですか?わかりません。

Exercise3.23

Exercise3.22 の処理を、加算、減算にとらわれずに実行できるようにせよ。

  def zipWith[A, B, C](al: List[A], bl: List[B])(f: (A, B) => C): List[C] = {
    def zipWith(a: List[A], b: List[B], r: List[C]): List[C] = {
      (a, b) match {
        case (Nil, _) => r
        case (_, Nil) => r
        case (Cons(ah, at), Cons(bh, bt)) => zipWith(at, bt, Cons(f(ah, bh), r))
      }
    }

    reverse(zipWith(al, bl, Nil))
  }

addPairwise を zipWith で処理すれば終了。

Winows10 がクソ重い

日記

症状的には定期的にHDアクセスが 100% に突入するというもの。

そういや前も食ったなと思い出して、対処した。
マシンを再セットアップしてからやってなかったなーと

  • IPv6 をオフ
  • OneDrive 同期を停止

毎回やらないと酷いことになるって最悪のエコシステムだな。

良かれと思ってというのはあるだろうが押し付けイクナイ

だからゲーム以外でWindows使いたくないんだよ…。

Scala 関数型デザイン&プログラミング:Exercize3.14-15

Scala 日記 勉強

相変わらず教科書はこれ。

進みは遅いが書かないと覚えなさそうだったので書く。

Exercise3.14

foldLeft or foldRight を使って、append 作れ

  def append[A](as: List[A], a: A): List[A] =
    foldRight(as, apply(a))((a, b) => Cons(a, b))

// printRec(List.append(List(1,2,3,4), 5))

って書いたら、模範解答はリストの結合だったという…
append つったら要素追加でしょうよ(;;

fpinscala/List.scala at master · fpinscala/fpinscala · GitHub

作り直し

  def append[A](as: List[A], a: List[A]): List[A] =
    foldRight(as, a)((a, b) => Cons(a, b))

// List.append(List(1,2,3,4), List(5, 6, 7))

Exercise 3.15

複数のリストを結合する関数を作れ

  def flatten[A](as: List[A]*): List[A] = {
    def flatten(head: List[A], tail: Seq[List[A]]): List[A] = {
      tail match {
        case t if t.isEmpty => head
        case t              => flatten(foldRight(head, t.head)((a, b) => Cons(a, b)), t.tail)
      }
    }
    as match {
      case a if a.isEmpty => Nil
      case a if a.size == 1 => a.head
      case a => flatten(a.head, a.tail)
    }
  }

// こうですか?わかりません
// printRec(List.flatten(
//    List(1,2,3), List(4,5,6), List(7,8,9)
// ))

仕様は多分満たしてるんだけど、実行効率がなぁ?
なんか違う気がしてきた。

fpinscala/List.scala at master · fpinscala/fpinscala · GitHub

やっぱりー(;;
なんかシグネチャ固定化して欲しいです。割と真面目に。

気を取り直してシグネチャから実装…ってこうとしか思い浮かばんから!

def concat[A](as: List[List[A]]): List[A] = foldRight(as, Nil: List[A])(append)

Scala 関数型デザイン&プログラミング:Exercize3.2 - 3.13

Scala 日記 勉強

前回 からの続き
教本はこれ

Exercise 3.2

問題

Listの最初の要素を削除する関数 tail を実装せよ。この関数の実行時間が一定であることに注意。List が Nil である場合、実装上の選択肢として他に何があるか。この質問については次章で再び取り上げる。

とのこと。

で、オブ脳な個人的に「あれ?tailってあるよね?trait でIF作ってって事?」と本家 scala.collections の List っぽく

sealed trait List[+A] {
  def head: A
  def tail: List[A]
}

case object Nil extends List[scala.Nothing] {
  override def head = sys.error("Empty head")
  override def tail = sys.error("Empty list")
}

case class Cons[+A](head: A, tail: List[A]) extends List[A]

で、なんか違うな…筆者は何を想定してるんだろう?と思って回答を見た。

fpinscala/List.scala at master · fpinscala/fpinscala · GitHub

違った…コンパニオンオブジェクトの話だったという…。
忘れたふりしてさらっと

  def tail[A](l: List[A]): List[A] = l match {
    case Nil           => Nil
    case Cons(_, tail) => tail
  }
object Exercise3_2 extends App {

  val result = List.tail(List(1, 2, 3, 4))

  def printRec(l: List[Int]): Unit = l match {
    case Nil => println("")
    case Cons(n, t) => {print(s"$n "); printRec(t)}
  }

  printRec(result)
}

Exercise 3.3

問題

Exercise 3.2 と同じ考え方に基づいて、List の最初の要素を別の値と置き換えるsetHead 関数を実装せよ。

  def head[A](l: List[A]): A = l match {
    case Nil        => sys.error("no head in empty")
    case Cons(a, _) => a
  }

/*
// 検証
object Exercise3_3 extends App {
  println(List.head(List(1,2,3,4,5)))
}
 */

どう考えたって例外しか思い浮かばない…

Exercise 3.4

先頭から N 個を削除する関数 drop を作れ

  def drop[A](l: List[A], n: Int): List[A] = {
    n match {
      case n if n <= 0 => l
      case _ => drop(tail(l), n - 1)
    }
  }

/*
object Exercise3_4 extends App {
  printRec(List.drop(List(1,2,3,4,5), 2))
}
*/

Exercise3.5

述語とマッチする場合に限り、Listからその要素までの要素を削除する dropWhile を実装せよ。

  def dropWhile[A](l: List[A], f: A => Boolean): List[A] = {
    l match {
      case Cons(h, t)  if f(h) =>  dropWhile(t, f)
      case _ => l
    }
  }

/*
object Exercise3_5 extends App {
  printRec(List.dropWhile[Int](List(1,2,3,4,5,6,7), _ < 5))
}
*/

Exercise 3.6

List の末尾を除く、すべての要素で構成された List を返す init 関数を実装せよ。

これは先頭から舐めるしかやり様がないので、要素 O(n) なんだろねー

  def reverse[A](l: List[A]): List[A] = {
    def inner(a: List[A], l: List[A]): List[A] = {
      l match {
        case Nil        => a
        case Cons(h, t) => inner(Cons(h, a), t)
      }
    }
    inner(Nil, l)
  }

  def init[A](list: List[A]): List[A] = {
    def inner(a: List[A], l: List[A]): List[A] = {
      l match {
        case Nil          => Nil
        case Cons(_, Nil) => a
        case Cons(h, t)   => inner(Cons(h, a), t)
      }
    }
    reverse(inner(Nil, list))
  }

/*
object Exercise3_6 extends App {
  val result: List[Int] = List.init(List(1,2,3,4,5))
  printRec(result)
}
*/

末尾再帰に拘らなければもっと短くなった気がする…今更か。

Exercise 3.7

考察問題なので端折る。

Exercise 3.8

foldRight 実装が前提になるので、まずは実装。
教科書通りの実装なのだが…

  def foldRight[A, B](as: List[A], z: B)(f: (A, B) => B): B = {
    as match {
      case Nil => z
      case Cons(x, xs) => f(x, foldRight(xs, z)(f))
    }
  }

…末尾再帰じゃない

  def foldRight[A, B](as: List[A], z: B)(f: (A, B) => B): B = {
    as match {
      case Nil         => z
      case Cons(x, xs) => foldRight(xs, f(x, z))(f)
    }
  }

これじゃあかんのかと思ったのだが…まぁ式に直すと f(5, f(4, f(3, f(2, f(1, z))) こんな感じになるから直感的ではないのかも?

object Exercise3_8 extends App {
  println(List(1,2,3,4,5))
  println(List.foldRight(List(1,2,3,4,5), Nil: List[Int])(Cons(_, _)))
}

結果はそう変わらず。
そりゃ head から順にとってけばそうなるよね

Exercise 3.9

リストの長さを計算する length を実装せよ。

  def length[A](as: List[A]): Long =
    foldRight(as, 0L)((_, b) => b + 1)
/*
object Exercise3_9 extends App {
  println(List.length(List(1,2,3,4,5)))
}
*/

Exercise 3.10

foldLeft を末尾再帰で実装せよ

…これってさっき書いた末尾再帰じゃね? (・・;)

  def foldLeft[A, B](as: List[A], z: B)(f: (B, A) => B): B = {
    as match {
      case Nil => z
      case Cons(x, Nil) => f(z, x)
      case Cons(x, xs)  => foldLeft(xs, f(z, x))(f)
    }
  }

Exercise 3.11

sum, product を foldLeft で実装せよ

  def sum(ints: List[Int]): Int = foldLeft(ints, 0)(_ + _)

  def product(sd: List[Double]): Double = foldLeft(sd, 1.0)(_ * _)

Exercise 3.12

リストを逆順する reverse 関数を作れ

あれ?上で書いた reverse 関数だよね?

Exercise 3.13

foldRight をベースに、foldLeft を記述することは可能か?その逆はどうか?

foldRight の初期値に関数突っ込めばいけるか?(つまり関数スタックを高階関数でやる)

  def foldLeftViaRight[A, B](as: List[A], z: B)(f: (B, A) => B): B =
    foldRight(as, (b:B) => b)((a, g) => b => g( f(b, a) ))(z)

  def foldRight[A, B](as: List[A], z: B)(f: (A, B) => B): B =
    foldLeft(reverse(as), z)((a, b) => f(b, a))

foldRight の方は割とすんなり。

Scala 関数型デザイン&プログラミング:Exercize3.1

続き

サンプルコード

package fpinscala.datastructures

sealed trait List[+A]

case object Nil extends List[scala.Nothing]

case class Cons[+A](head: A, tail: List[A]) extends List[A]

object List {

  def sum(ints: List[Int]): Int = ints match {
    case Nil         => 0
    case Cons(x, xs) => x + sum(xs)
  }

  def product(sd: List[Double]): Double = sd match {
    case Nil          => 1.0
    case Cons(0.0, _) => 0.0
    case Cons(x, xs)  => x * product(xs)
  }

  def apply[A](as: A*): List[A] =
    if (as.isEmpty) Nil else Cons(as.head, apply(as.tail:_*))
}

があるときに、下記の結果はなんだ!?

  val x = List(1,2,3,4,5) match {
    case Cons(x, Cons(2, Cons(3, Cons(4, _)))) => x
    case Nil => 42
    case Cons(x, Cons(y, Cons(3, Cons(4, _)))) => x + y
    case Cons(h, t) => h + List.sum(t)
    case _ => 101
  }

見たまんま

Scala 関数型デザイン&プログラミング:Exercize2.2 - 2.5

Scala 日記 勉強

引き続き勉強がてら Exercise をやってみる。

Exercise 2.2

お題:配列が任意の比較関数でソートされているか判定せよ
ただし、メソッドシグネチャdef isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean 固定。

…generic な高階関数なだけか…

object Exercise2_2 extends App {
  def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = {
    if (as.size < 2) {
      true
    } else {
      ordered(as.head, as.tail.head) &&
        isSorted(as.tail, ordered)
    }
  }

  def isOrdered(a: Int, b: Int) = a < b

  println(s"test 1 to 10 ordered ${isSorted((1 to 10).toArray, isOrdered)}")
  println(s"test 10 to 1 ordered ${isSorted((1 to 10).reverse.toArray, isOrdered)}")
}

まぁこれ位なら…

Exercise 2.3

お題:この関数を実装しろ

def curry[A, B, C](f: (A, B) => C): A => (B => C)

なんだ、ただのカレーか

object Exercise2_3 extends App {
  def curry[A, B, C](f: (A, B) => C): A => (B => C) = {
    def curried(a1: A) = (a2: B) => f(a1, a2)
    curried
  }

  def createFilledArray(i: Int, b: Boolean): Array[Boolean] = Array.fill(i)(b)

  val curried = curry(createFilledArray)
  val arr: Array[Boolean] = curried(10)(true)

  println(arr.toSeq)
}

Exercise 2.4

お題: curry の逆向きを行う、uncurryを作成せよ

object Exercise2_4 extends App {
  def uncurry[A, B, C](f: A => (B => C)): (A, B) => C = {
    def unc(a1: A, a2: B) = f(a1)(a2)
    unc
  }

  def createFilledArray(i: Int)(b: Boolean): Array[Boolean] = Array.fill(i)(b)

  val curried = uncurry(createFilledArray)
  val arr: Array[Boolean] = curried(10, true)

  println(arr.toSeq)
}

Exercise 2.5

お題:二つの関数を合成する高階関数を作成せよ。

object Exercise2_5 extends App {
  def compose[A, B, C](f1: B => C, f2: A => B): A => C = {
    def com(v: A) = f1(f2(v))
    com
  }

  def toStr(d: Double) = d.toString
  def toDouble(i: Int) = i.toDouble

  println(compose(toStr, toDouble)(65535).getClass)
}

末尾再起に比べたら緩い…。