One IT Thing

IT業界を楽しむ為の学習系雑記

angular

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

投稿日:2019年7月16日 更新日:

正規表現を可視化したり、ヒットした文字列をハイライトしてくれるWebサイトやチートシートは沢山紹介されていてニーズを満たしてくれます。

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

https://rubular.com/

気分転換に作っていた効率化ツールにこういう機能を入れようと思ったのですが、自分のアプリに組み込めるライブラリは意外と無いんですよね。

色々試行錯誤してみました。

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

3年前から更新無し。作者さんが更新する気NULLなのが伝わってきます。

試しに適当な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にブラウザアクセス。
期待した機能が実現出来ました。

あまりライブラリ公開されない理由

HTMLコードを返却するライブラリにするとJavascript埋め込みが出来てしまい、サニタイズ処理が面倒だからライブラリが少なかったりするんでしょうかね。

今回の実装も、悪意のある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のサニタイズ処理を無効にした場合は、セキュリティの担保はプログラマがちゃんとやってね。ということですね。

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

-angular
-

執筆者:

関連記事

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

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

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

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

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

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

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

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

Angularのテンプレート評価式にビット演算を使うとTemplate parse errorが発生する

AngularのテンプレートHTMLでビット演算をすることは禁じられているので代替手段を考えます。 目次1 事象2 原因3 対処 事象 CSSクラスをビット演算で切り替えるテンプレートを書きました。c …


shingo nakanishi。東京で消耗中の職歴20年越え中年ITエンジニアです。「生涯現役プログラマを楽しむ」ことができる働き方探しをライフワークにしています。

19歳(1996年)から書き始めた個人日記が5,000日を超え、残りの人生は発信をして行きたいと思い、令和元日からこのサイトを開始しました。勉強と試行錯誤をしながら、自分が経験したIT関連情報を投稿しています。