コンテンツにスキップ

2023

Markdownのリンクを新規タブで開く

前提

  • remark, remark-rehype, rehype-stringify がインストール済みであること
  • npm i --save-dev remark remark-rehype rehype-stringify

対応方法

rehype-external-linksを使って target 属性を指定します

設定方法

rehype-external-linksをインストールします。

npm i --save-dev rehype-external-links

コンポーネント markdownToHtml.js が以下のようなものだとします:

import { remark } from "remark";
import remarkRehype from "remark-rehype";
import rehypeStringify from "rehype-stringify";
import rehypeExternalLinks from "rehype-external-links";

export const markdownToHtml = async (markdown: string) => {
  const result = await remark()
    .use(remarkRehype, { allowDangerousHtml: true })
    .use(rehypeExternalLinks, {
      target: "_blank",
      rel: ["noopener noreferrer"],
    })
    .use(rehypeStringify)
    .process(markdown);
  return result.toString();
};

markdownToHtml.js を使ってページを表示します。

import { InferGetStaticPropsType, NextPage } from "next";
import { markdownToHtml } from "../../lib/markdownToHtml";

type Props = InferGetStaticPropsType<typeof getStaticProps>;

const Home: NextPage<Props> = ({ html }) => {
  return (
    <div
      dangerouslySetInnerHTML={{
        __html: html,
      }}
    ></div>
  );
};

export const getStaticProps = async () => {
  return {
    props: {
      html: await markdownToHtml(
        "[rehype](https://github.com/rehypejs/rehype)"
      ),
    },
  };
};

export default Home;

このように出力されます。

<div>
  <p>
    <a
      href="https://github.com/rehypejs/rehype"
      target="_blank"
      rel="noopener noreferrer"
    >
      rehype
    </a>
  </p>
</div>

Chaliceでリクエストパラメータベースのオーソライザーを作成する

まず、Chaliceの定義から。

Chalice は、python でサーバーレスアプリを書くためのフレームワークです。AWS Lambda を利用したアプリケーションを素早く作成し、デプロイすることができます。提供するものです。

  • アプリの作成、デプロイ、管理のためのコマンドラインツール
  • Amazon API Gateway、Amazon S3、Amazon SNS、Amazon SQS、およびその他の AWS サービスと統合するためのデコレーターベースの API。
  • IAM ポリシーの自動生成

Chalice のオーソライザーはトークンベースのオーソライザーしか用意されていません。リクエストパラメータベースで使いたい場合は、自分で拡張する必要があります。検索しまくっても全然出てこないので、サンプルコードを残しておきます。

from typing import Any, Dict, List, Optional

from chalice import Chalice
from chalice.app import Authorizer

app = Chalice(app_name="custom-request-base-authorizer")


class CustomAuthorizer(Authorizer):

    _AUTH_TYPE = "custom"

    def __init__(
        self,
        name: str,
        authorizer_uri: str,
        ttl_seconds: int = 300,
        header: str = "Authorization",
        invoke_role_arn: Optional[str] = None,
        scopes: Optional[List[str]] = None,
        identity_sources: Optional[List[str]] = [],
    ) -> None:
        self.name = name
        self._header = header
        self._authorizer_uri = authorizer_uri
        self._ttl_seconds = ttl_seconds
        self._invoke_role_arn = invoke_role_arn
        self.scopes = scopes or []
        self._identity_sources = identity_sources

    def to_swagger(self) -> Dict[str, Any]:
        # パラメータ名を変換
        # ヘッダーにしか対応してません
        # クエリパラメータなどに対応したい場合は、自分で実装してください
        identity_source = ",".join(
            [
                f"method.request.header.{identity_source}"
                for identity_source in self._identity_sources
            ]
        )

        swagger: Dict[str, Any] = {
            "in": "header",
            "type": "apiKey",
            "name": self._header,
            "x-amazon-apigateway-authtype": self._AUTH_TYPE,
            "x-amazon-apigateway-authorizer": {
                "type": "request",
                "identitySource": identity_source,
                "authorizerUri": self._authorizer_uri,
                "authorizerResultTtlInSeconds": self._ttl_seconds,
            },
        }
        if self._invoke_role_arn is not None:
            swagger["x-amazon-apigateway-authorizer"][
                "authorizerCredentials"
            ] = self._invoke_role_arn
        return swagger


region = "ap-northeast-1"   # リージョンを指定
lambda_arn = "" # LambdaオーソライザーのARNを指定
authorizer_uri = f"arn:aws:apigateway:{region}:lambda:path/2015-03-31/functions/{lambda_arn}/invocations"

authorizer = CustomAuthorizer(
    "CustomRequestBaseAuthorizer",
    authorizer_uri=authorizer_uri,
    identity_sources=["Authorization", "X-Request-Id"],
)


@app.route("/private", authorizer=authorizer)
def private():
    return {"hello": "world"}

さらに細かい設定をしたい場合は、x-amazon-apigateway-authorizer オブジェクトで確認してください。

参考

docusaurus + CloudFront + S3で直リンクOKにする

docusaurusCloudFront + S3でホスティングしたとき、直リンでアクセスできるパスが制限されています。

  • NG: https://example.com/foo
  • OK: https://example.com/foo/index.html
  • OK: https://example.com
  • ※デフォルトルートを設定したときのみ OK

https://example.com/fooを参照したい場合は、まずhttps://example.comにアクセスしてページ内リンクからhttps://example.com/fooへ移動しないといけません。

これが地味に使いにくい。URL をチームに共有するとき、アドレスバーをコピペするとhttps://example.com/fooとなるので、アクセスするときに手間がかかります。

Lambda@edgeを使って解決します。

手順

  1. Lambda を作成する
  2. Lambda のバージョンを作成する
  3. IAM ロール周りを修正する
  4. CloudFront をトリガーに設定する

1. Lambdaを作成する

us-east-1リージョンに Lambda を作成します。 ランタイムはNode.js 16.xを選択しました。 ロールは基本的な Lambda アクセス権限で新しいロールを作成で作成しました。

export const handler = async (event, context, callback) => {
  const request = event.Records[0].cf.request;

  const olduri = request.uri;

  if (isExistExtension(oldurl)) {
    // 拡張子があれば、そのまま返す
    return callback(null, request);
  }

  // 末尾にindex.htmlを付与する
  // - https://example.com/foo → https://example.com/foo/index.html
  // - https://example.com/foo/ → https://example.com/foo/index.html
  const newuri = (olduri.endsWith("/") ? olduri : olduri + "/") + "index.html";
  request.uri = newuri;

  return callback(null, request);
};

/**
 * 拡張子存在チェック
 */
function isExistExtension(url) {
  const ext = url.split(".").pop().trim();

  // 拡張子がない場合は、ext = url となる
  return ext !== url;
}

2. Lambdaのバージョンを作成する

右上にある「アクション」プルダウンや「バージョン」タブから「新しいバージョンを発行」をする。 入力項目は適当でよいです。

3. IAM ロール周りを修正する

1. Lambdaを作成するで作成したロールに対して色々やります。

ポリシーの追加

新たに以下のポリシーを追加します。[lambdaの関数名]には1. Lambda を作成する作成時の関数名を入力します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole",
        "cloudfront:UpdateDistribution"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["lambda:GetFunction", "lambda:EnableReplication"],
      "Resource": "arn:aws:lambda:us-east-1:371422377734:function:[lambdaの関数名]:*"
    }
  ]
}
信頼関係の変更

「信頼関係」タブがあるので、edgelambda.amazonaws.comを追加します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": ["lambda.amazonaws.com", "edgelambda.amazonaws.com"]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

4. CloudFront をトリガーに設定する

右上にある「アクション」プルダウンから「Lambda@Edge」へのデプロイを選択します。

item value
Distribution 対象の CloudFront
Cache behavior *
CloudFront event Origin request
Confirm deploy to Lambda@Edge On

これでデプロイすれば完了です。

参考

2023年の目標

今年の目標を立てました。最近気持ちが追いつかないので、頑張りすぎない程度の目標です。

  • CODE COMPLETE 上を買う
  • CODE COMPLETE 上を流し読みする
  • 転職に向けて何か動く
  • 月1は書籍を読む
  • 月1はブログを更新する
  • お酒をできるだけ控える