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
-

執筆者:

関連記事

ブラウザで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 …

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

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

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

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

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

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

 

shingo.nakanishi
 

東京在勤、職歴2n年中年ITエンジニアです。まだ開発現場で頑張っています。

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

私と同じく、今後IT業界で生計を立てて行きたいと考えている方や、技術共有したいけど仲間が居なくて孤独、といった方と一緒に成長、知識共有して行けたら楽しいな、と思っています。