angular

正規表現結果をHTMLコード化してマッチ部分をハイライト表示

投稿日:2019年7月16日

やりたかったのは「Rubular」が提供してくれるマッチした部分をハイライトしてくれる機能。

https://rubular.com/

ちょっとしたツールにこういう機能を入れようと思ったのですが、ニーズを満たしてくれるライブラリが意外と無くて色々試行錯誤してみました。

イメージに近いNPMモジュール

3年前から更新無し。試しに適当なnpm initディレクトリを作ってインストール。

C:\src\js\regexp_viewer>npm install regex-viewer

+ regex-viewer@1.0.2

サンプル通りの内容をindex.jsに書いて保存。
メール文字列から電話番号にマッチさせてハイライトさせるストーリーで。

"use strict";

var viewer = require("regex-viewer");

// ダミーメール文字列
var str = `
お世話になっております。○○です。
詳細は口頭でお話させて頂きたいと存じます。
私の個人携帯:999-999-9999
または
代表番号:99-9999-9999
までご連絡下さい。
`;
var regex = /\d{2,4}-\d{2,4}-\d{4}/gi;

viewer(str, regex);

node indexで実行。

ハイライトされますが、ブラウザが起動してしまいます。

うーん、ブラウザが起動するのではライブラリとしては使えません。
HTMLコードだけ返して欲しいけどソースを見てもそういったモードは無さそうです。

諦めてちょんプロを作って検証

前述のNPMモジュールと同様、正規表現マッチした文字列をスタイリングしたspanタグで囲って返却する方式で実装検証してみます。

let replacement = mail.replace(
    regex,
    str =>
        `<span style="color: white;background-color: red;border-radius: 5px;">` +
        str +
        `</span>`
);

Angular8 + Angular Materialのプロジェクトで検証。mat-cardのコンテンツとしてハイライトされたメール文言がバインドされるようにします。

    <mat-card>
        <mat-card-title>
            メール1
        </mat-card-title>
        <mat-card-subtitle>
            日付
        </mat-card-subtitle>
        <mat-card-content [innerHtml]="safeHtml">
        </mat-card-content>
    </mat-card>

Angularはバインド結果の文字列にHTMLタグが含まれているとCSRF対策でエスケープされ、ブラウザ画面上でそのまま<span>が表示されます。

今回はDomSanitizerを使って検証済みのコードである旨をマーク、Angularのエスケープ処理を回避します。

import { Component } from "@angular/core";
import { DomSanitizer, SafeHtml } from "@angular/platform-browser";

@Component({
    selector: "app-root",
    templateUrl: "./app.component.html",
    styleUrls: ["./app.component.scss"]
})
export class AppComponent {

    // 正規表現処理後文字列、DomSsanitizerによってセーフマーク
    safeHtml: SafeHtml;

    // サンプル原文
    mail: string = `
お世話になっております。○○です。
詳細は口頭でお話させて頂きたいと存じます。
私の個人携帯:999-999-9999
または
代表番号:99-9999-9999
までご連絡下さい。
`;

    constructor(private sanitizer: DomSanitizer) {
        this.safeHtml = this.extractPhoneNumber(this.mail);
    }

    public extractPhoneNumber(mail: string): SafeHtml {
        let regex = /\d{2,4}-\d{2,4}-\d{4}/gi;

        // マッチした文字列をハイライトする為のspanタグを挿入
        let replacement = mail.replace(
            regex,
            str =>
                `<span style="color: white;background-color: red;border-radius: 5px;">` +
                str +
                `</span>`
        );

        // 中に含まれているタグを安全なものとしてマーク
        let safeHtml: SafeHtml = this.sanitizer.bypassSecurityTrustHtml(
            replacement
        );

        return safeHtml;
    }

実行結果

ng serveしてhttp://localhost:4200にブラウザアクセス。期待した機能が実現出来ました。

ただ、bypassSecurityTrustHtml()を使ったことによって悪意のあるJavascriptコードがメール本文に入っていた場合はブラウザに埋め込まれる可能性があります。

AngularのDomSanitizer APIリファレンスには以下の記載があります。


Calling any of the bypassSecurityTrust... APIs disables Angular’s built-in sanitization for the value passed in. Carefully check and audit all values and code paths going into this call. Make sure any user data is appropriately escaped for this security context. For more detail, see the Security Guide.

各種DomSanitizer#bypassSecurrityTrust~APIを呼ぶと譲渡されたデータに対するAngularの組み込みサニタイズが無効になります。この処理に入る全ての値とコードパスを慎重にチェック、監査してください。このセキュリティコンテキスト内ではユーザのデータが適切にエスケープされるようにしてください。


https://angular.io/api/platform-browser/DomSanitizer

DomSanitizerを使ってAngularのサニタイズ処理を無効にした場合は、JS埋め込みされないようにする担保をプログラマがちゃんとするように、ということですね。

使うときは入ってくるデータの事前検証をして、出来ればDomSanitizerは使わない方法で実装したいところです。

-angular
-

執筆者:

関連記事

compodocでAngularプロジェクトのビジュアルなドキュメントを自動生成する

Java、C、Pythonのドキュメントを自動生成する際にDoxygenを使えばクラス図や呼び出し図、呼び出され図を作れて便利です。 しかしDoxygenはTypescriptには対応しておらず、.t …

Angular11から12にアップデートしたらng serveがproductionモードで起動するようになってしまう

既存のAngular11のプロジェクトを12に上げた際に発生。 目次1 環境2 事象3 原因4 対処5 根本原因6 まとめ 環境 Windows 11Node.js 14.15.1Angular13リ …

ブラウザでRSA暗号化したデータをサーバで復号する(Angular + JSEncrypt、Spring MVC)【後編】

前回の続きです。One IT ThingブラウザでRSA暗号化したデータをサーバで復号する(Angular + JSEncrypt、Spring …https://one-it-thing.com …

Angular4.4のHTTP通信処理にタイムアウトを設定をすると「timeout is not a function」エラーが発生する

目次1 事象2 原因3 対処4 まとめ 事象 Angular4.3で追加されたHttpClientModuleに移行せず、HttpModuleを使い続けているアプリで、とある理由からpackage-l …

Angular8のDefferential Loadで作られたPolyfill抜きJSがブラウザに読み込まれるまでを観察してみる

Angular単体では約30%の削減でした。 2019/05にリリースされたAngular8では、ビルド結果として生成されるバンドルファイルがES6(ES2015)対応しているモダンブラウザ用、とそう …

 

shingo.nakanishi
 

東京在勤、1977年生まれ、IT職歴2n年、生涯技術者として楽しく生きることを目指しています。デスマに負けず健康第一。