メインコンテンツへスキップ
見出し画像

【IT】ソースコード用簡易個人情報マスキングツール(Svelte+Tailwind CSS)

    皆さま
    こんにちは

    最近では、ChatGPTやGeminiなどのAIチャットを使って、プログラムの作成や修正を行う方も多いと思います。

    こうしたやり取りでは、ソースコードやエラーログをそのまま貼り付ける場面が多くありますが、その中に APIキー・メールアドレス・ユーザー名 などの個人情報が含まれていることがあります。
    これらを投稿前に毎回手作業で置き換えるのは、正直かなり手間です。

    そこで今回は、PCローカル(スタンドアロン)で動作する「簡易マスキングツール」 を作成します。インターネット接続不要で、送信リスクをゼロにしながら、一発でコードやログを安全な形に変換できます。

    本記事は、以下の2パート構成です。
    ・無料パート:最小構成での作り方(誰でも試せる)
    ・有料パート:より多くのケースに対応した拡張版コード & 編集可能なマスク設定ファイル
    ※ご注意:本ツールは“漏れを最小化”する学習用サンプルです。完全な匿名化を保証するものではありません。 重要情報の外部共有前には目視確認と社内ポリシーに従ったレビューを必ず実施してください。

    💡こんな人におすすめ
    ・
    AI にソースコードを貼る前に一発で個人情報を消したい
    ・
    インターネットに送信しないオフライン処理を求めている
    ・自分用にマスクルールを簡単に編集したい

    1. 環境準備

    🖥 開発環境

    • PC:MacBook Air (M1, macOS 14.5)

    • フレームワーク:Svelte v5

    • 言語:TypeScript

    • 実行方法:ブラウザで動作するオフラインアプリ(サーバ不要)

    ※ 本記事の手順は macOS(Apple Silicon)環境でのみ検証済み です。
    WindowsやLinuxでも動作する可能性はありますが、未検証のため動作保証はできません。

    a. 前提条件

    npm と nodeがインストールされていること確認します。
    未導入の場合は、過去記事をご参照ください。

    $ npm -v
    11.3.0
    
    $ node -v
    v22.12.0

    b. Svelteのインストール

    以下のコマンドでインストールします。
    今回は、Svelte単体をTypeScriptを選択します。

    $ npm create vite@latest
    
    > npx
    > create-vite
    
    │
    ◇  Project name:
    │  mask-app-log-svelte1
    │
    ◇  Select a framework:
    │  Svelte
    │
    ◇  Select a variant:
    │  TypeScript
    │
    ◇  Scaffolding project in /Users/user/info_remval/mask-app-log-svelte1...
    │
    └  Done. Now run:
    
      cd mask-app-log-svelte1
      npm install
      npm run dev
    
    $ cd mask-app-log-svelte1
    
    $ npm install

    c. Svelteのクリーンアップ

    src/app.cssは空に
    src/lib/Counter.svelteは削除します。

    src/App.svelteは、元々のコードを削除して以下の通りとします。
    (最小構成)

    <script lang="ts">
    
    </script>
    
    <main>
      <h1 class="text-3xl font-bold underline">
        Hello world!
      </h1>
    
    
    </main>
    
    <style>
      /* 必要に応じて Tailwind CSS の代わりにここに通常の CSS を追加してもOK */
    </style>

    d. Tailwind CSSの導入

    今回、viteで導入しておりますのでTailwind CSSのサイトの案内通りに
    導入します。

    プロジェクトディレクトリに移動してらインストールします。

    $ cd mask-app-log-svelte1
    
    $ npm install tailwindcss @tailwindcss/vite
    
    added 84 packages, and audited 129 packages in 3s
    
    19 packages are looking for funding
      run `npm fund` for details

    次にvite.config.tsにtailwindcssの設定を追加します。
    ※合わせてbuild時の相対パスの設定を行います。

    project-dir/vite.config.ts

    import { defineConfig } from 'vite'
    import { svelte } from '@sveltejs/vite-plugin-svelte'
    import tailwindcss from '@tailwindcss/vite'  // →追加
    
    // https://vite.dev/config/
    export default defineConfig({
      base: './',                      // ← 相対パスに強制
      plugins: [
        svelte(),
        tailwindcss(),                 // →追加
     ], 
    })

    app.cssにtailwindcssの呼び出し設定を挿入します。
    ※元のCSSは、削除してから挿入ください。

    src/app.css

    @import "tailwindcss";

    2.マスキングツール作成(学習用サンプル)

    1.  🧼 sanitizeText.ts の追加

    src/sanitizeText.ts にマスク処理のロジックを定義します。
    (学習用のサンプルコードです。)

    // 学習用のサンプルコードです。
    
    // src/lib/sanitizeText.ts
    
    /**
     * 個人情報や機密情報を含む可能性のある行を自動でマスクします
     * チャットや掲示板投稿前の事前チェックに使用します
     * 実際のマスクパターンをこのファイルに追加していきます。
     */
    export function sanitizeText(input: string): string {
      return input
        // ✅ メールアドレス
        .replace(/[\w.-]+@[\w.-]+\.\w+/g, '[email masked]')
    
        // ✅ パスワード代入っぽい行
        .replace(/(password\s*=\s*)['"].+?['"]/gi, '$1"[masked]"')
    
        // ✅ ファイルパス(Linux/macOS/Windows)
        .replace(/\/home\/\w+|\/Users\/\w+|C:\\Users\\\w+/gi, '/[user]')
    
        // ✅ GitHubユーザー名入りURL
        .replace(/https:\/\/github\.com\/[\w-]+\//gi, 'https://github.com/[user]/')
    
        // ✅ コメントや署名(簡易)
        .replace(/#\s*by\s+\w+/gi, '# by [user]')
    
        // ✅ IPアドレス(IPv4)
        .replace(/\b\d{1,3}(?:\.\d{1,3}){3}\b/g, '[ip masked]');
    }
    

    2. 💻src/App.svelte の編集

    src/sanitizeText.tsを呼び出して、入力用のテキストエリアを追加します。
    (学習用のサンプルコードです。)

    <!-- 学習用のサンプルコードです。 -->
    
    <script lang="ts">
      import { sanitizeText } from './lib/sanitizeText';
      let input = '';
      let output = '';
    
      function handleSanitize() {
        output = sanitizeText(input);
      }
    
      function handleClear() {
        input = '';
        output = '';
      }
    </script>
    
    <main class="p-6 max-w-3xl mx-auto">
      <h1 class="text-2xl font-bold mb-4">SanityPaste</h1>
    
      <!-- 入力欄 -->
      <label for="inputText" class="block mb-2 font-semibold">入力</label>
      <textarea
        id="inputText"
        bind:value={input}
        rows="10"
        class="w-full border p-2 mb-4 rounded"
      ></textarea>
    
      <!-- 実行ボタン -->
      <button
        onclick={handleSanitize}
        class="bg-blue-600 text-white px-4 py-2 rounded"
      >
        マスク実行
      </button>
    
      <button 
        onclick={handleClear} 
        class="bg-gray-400 hover:bg-gray-500 text-white px-4 py-2 rounded"
      >
        クリア
      </button>
    
      <!-- 出力欄 -->
      <label for="outputText" class="block mt-6 mb-2 font-semibold">出力(マスク後)</label>
      <textarea
        id="outputText"
        readonly
        value={output}
        rows="10"
        class="w-full border p-2 bg-gray-100 rounded"
      ></textarea>
    </main>
    
    <style>
      /* 必要に応じて Tailwind CSS の代わりにここに通常の CSS を追加してもOK */
    </style>
    

    3. 🚀 ビルド

    ビルドするとdist/ フォルダにビルド成果物(index.html + assets)一式が出力されます。

    $ npm run build
    
    > mask-app-log-svelte1@0.0.0 build
    > vite build
    
    vite v7.0.6 building for production...
    ✓ 104 modules transformed.
    dist/index.html                  0.48 kB │ gzip: 0.31 kB
    dist/assets/index-xxxx.css       5.67 kB │ gzip: 1.92 kB
    dist/assets/index-xxxx.js       23.06 kB │ gzip: 9.68 kB

    3.動作テスト

    1. プレビューにて確認

    $ npm run preview
    
    > mask-app-log-svelte1@0.0.0 preview
    > vite preview
    
      ➜  Local:   http://localhost:4173/
      ➜  Network: use --host to expose
      ➜  press h + enter to show help

    メールアドレスやパスワードがマスクされていることを確認
    ※http://localhost:4173/ で確認

    画像

    2. buildしたindex.htmlを直接起動

    file://index.htmlは、
    エラーとなり画面は真っ白となる。
    CORS(Cross-Origin Resource Sharing、クロスオリジン・リソース・シェアリング)のため、ファイルから起動の際は、エラーとなる。

    画像

    CORS(Cross-Origin Resource Sharing、クロスオリジン・リソース・シェアリング)とは、異なるオリジン(ドメイン、ポート、またはプロトコルが異なる)間でのリソース共有を許可・制御するための仕組みです。主にWebブラウザが関与するセキュリティ機構であり、JavaScriptで外部のAPIやリソースにアクセスする際に関係してきます。

    🔒 なぜCORSが必要か?

    ブラウザには「同一オリジンポリシー(Same-Origin Policy)」というセキュリティ制限があります。これは、あるWebページが自分と異なるオリジンのリソースに自由にアクセスすることを防ぐための仕組みです。

    例:https://example.com にあるWebページのJavaScriptは、通常、https://api.example.com や http://anotherdomain.com にあるAPIには直接アクセスできません。

    これでは、毎回サーバを起動するか、VSCodeのGo Liveで使用するかになり、利便性がおちます。
    かと言ってVercel等にアップするのは、個人情報をマスクする意味合いで
    いただけません。
    次項で対策を行なって行きます。
    ※セキュリティを弱めた方法でChromeを起動すると確認できますが、おすすめではありません。

    <<ご参考>>セキュリティを無効化したChromeの起動方法

    open -na "Google Chrome" --args --disable-web-security --user-data-dir="/tmp/chrome"

    4.対策

    1. 原因と対策方針

    原因:
    CORSポリシーにより、file:// から読み込もうとすると拒否されます。

    • index.html の中で <script type="module" src="/assets/index-xxxx.js"> のようにビルドされた JavaScript を読み込んでいます。

    • しかし、file:// では相対パスやモジュール解決がうまく機能しないため、JSの読み込みに失敗し、結果として真っ白になります。

    対策:
    index.htmlへJavaScriptもCSSも組み込むこととします。

    2. 対策(index.htmlへ集約)

    • dist/index.html を読み込み

    • dist/assets/*.css を取得 → <head> に <style>…</style> を挿入

    • dist/assets/*.js を取得 → </body> 直前に <script>…</script> を挿入

    • 出力先:dist/index_standalone.html(単一ファイル)

    • 実行:bash make-standalone.sh(購入者向けに配布)

    ※file:// ではビルド後の分割ファイル解決に失敗しやすいため、依存を1枚にまとめて読み込みエラーを避けます。

    $ ./make-standalone.sh
    🔧 スタンドアロンHTMLを生成中...
    ✅ favicon付きスタンドアロンHTMLを生成しました: dist/index_standalone.html
    

    3. 再確認

    出力された「dist/index_standalone.html」をダブルクリックして
    ページを表示します。
    マスクされるか確認します。

    画像

    ⭐️ここまでのまとめ(無料部分)

    ・Svelte + Vite + Tailwind の最小プロジェクトが構築
    ・簡易マスキングがローカルで動作することを確認
    ・スタンドアロンHTML化の流れ理解
    となります。
    この続きを(有料版:500円)では、実運用向けの完成コードと設定例を提供します。

    アプリ概要

    このツールは、開発や運用の現場で扱うコードやログ内の特定パターンの個人情報を自動的にマスク(置き換え)するスクリプトです。
    環境変数、APIキー、メールアドレス、住所、電話番号、法人名、IPアドレスなど、事前に定義されたパターンに基づき検出し、安全な形式に変換します。

    開発者やチームがソースコードや共有ログを外部に渡す際、情報漏洩のリスクを減らすことを目的としています。

    主なマスク対象とルール

    このツールは、スクリプト内で設定された関数と外部JSON(mask-config.json)で設定されたルールに基づき、以下の情報を自動マスクします。

    • 環境変数(.env形式・コード内)
      APIキーやアクセストークンなど
      除外パターンに記載されたものはマスク対象外

    • メールアドレス
      一般的な形式(user@example.comなど)を検出してマスク

    • 郵便番号と住所
      都道府県名のみ残して市区町村以下をマスク(漢字のみ対応)
      スペース入りの住所は未対応
      除外住所リストにある固有名詞(大学名など)はマスク対象外

    • 氏名(漢字・カタカナ)
      sensitiveWords に登録された名前のみマスク対象
      JSON形式で外部管理(mask-config.json)

    • 電話番号
      固定電話・携帯電話の形式を検出してマスク

    • 法人名
      「株式会社」「有限会社」などの前株・後株を除き、企業名部分をマスク

    • IPアドレス
      IPv4形式を検出してマスク

    • コメント内の特定キーワード
      author, reviewer, updated などのキーワードを含むコメントをマスク
      除外パターンに記載された場合は対象外

    • JSON形式のキーと値
      JSON構造内で、mask-config.json に定義されたキー(例:email, phone, password など)に該当する場合、その値をマスク
      除外パターンに一致するキーや値は対象外

    注意事項(必ずお読みください)

    • 対象範囲:本コードは作者が把握している一部パターンのみをマスクします。完全な匿名化は保証しません。

    • 運用前確認:機微情報の外部共有前に、目視確認と社内ポリシーに沿ったレビューを必ず実施してください。

    • カスタマイズ:不足分は mask-config.json の編集やコード修正で拡張可能です(サポート/個別改修は行いません)。

    • 利用条件:購入者の個人利用に限る。再配布・販売は禁止です。

    • 免責:本コードの利用により生じたいかなる損害やトラブルについて、作者は一切責任を負いません。

    • 検証環境:macOS(Apple Silicon)。Windows/Linux は挙動差の可能性あり。

     
     
    インフラエンジニアとして実務メモを、 写真作家として写真物語を、 童話作家として物語を書いています。 写真作品は、ポートフォリオサイトとしてまとめていく予定です。

    あなたへのおすすめ