拡張機能で社内フォルダへのリンクを開けるようにしたい_NativeMessaging

社内で使用しているwebシステムで、社内の別フォルダへのリンクを記載しておく。という事をよくします。
でも通常ブラウザからローカルリンクはセキュリティ的に開けないです。
今回の場合は、社内のローカルサーバーで管理されたサイトに書いている社内のローカル共有フォルダへのリンクなので、リンクから飛びたくなりました。
ということで拡張機能のNativeMessagingを試してみました。

似たことをリンク先でしています。

https://qiita.com/msms/items/44f87c45f8c286444eff

# つくった拡張機能
## コンテンツ
- 内容入力する時に、毎回aタグを書いてリンクにするのが手間なので、後からURLにaタグをつける処理を入れる
- NativeMessaging経由で開きたいので`href='javascript:void(0)`としてそのままでは開かないようにする
- リンククリック時に`background.js`へURLを渡す
- 呼び出し先でエラーとかがあれば、アラートを出す

```contents.js
// 元のサイトではURLを入力してもテキストのままなのでリンクに変更する
// hrefでの遷移はしないようにする　NativeMessaging経由にするため
const qs = document.querySelectorAll(".Reference, .multiple-lines");
const exp = /((\\\\)[^\<\>"\n\r]*)/gi;
for (let i = 0; i < qs.length; i++) {
  const r = qs
    .item(i)
    .textContent.replace(exp, "<a href='javascript:void(0)'>$1</a>");
  qs.item(i).innerHTML = r;
}

// 指定のaタグにクリックイベントを追加
// 実行するのは192.168.xxx.xxだけと限定しておく
document.querySelectorAll("a").forEach((e) => {
  if (e.text.startsWith("\\\\192.168.xxx.xx")) {
    e.addEventListener("click", NativeMessagingPath);
  }
});
// アプリを呼び出すためbackgroundへ値を渡す処理
function NativeMessagingPath(e) {
  // 処理中はマウスアイコンをぐるぐるに変更
  document.body.style.cursor = "wait";
  chrome.runtime.sendMessage(
    e.target.text, // backgroundに渡すデータ
    function (response) {
      // 処理が終わったらマウスアイコンを戻す
      document.body.style.cursor = "auto";
      // クライアント処理結果
      if (response.return) {
        // 返された文字がerrorならアラート
        if (response.msg.startsWith("error")) {
          alert(response.msg);
        }
      } else {
        alert("NG" + response.msg);
      }
    }
  );
}

```

## バックグラウンド
- `contents.js`から呼ばれたら、ネイティブアプリ`nativeexcute`へその値を渡して実行する
- ネイティブアプリからの出力は、`contents.js`へ返す
- エラーなら`contents.js`の方でアラートを出す
```background.js
// contents.jsからの呼び出し時の処理
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
  try {
    // 外部アプリを呼ぶ
    chrome.runtime.sendNativeMessage(
      "nativeexcute",  // この名前をマニフェストで設定した呼び出すアプリ名にする
      { value: request },
      function (response) {
        // contents.jsに値を返す
        sendResponse({
          return: true,
          msg: response.value,
        });
      }
    );
  } catch (error) {
    // エラー時
    sendResponse({
      return: false,
      msg: "error",
    });
  }
  return true;
});

```
## 拡張機能のマニフェスト
```manifest.json
{
  "name": "linklink",
  "description": "リンクを開く",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": [
    "alarms",
    "tabs",
    "nativeMessaging"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": [
        "http://192.168.xxx.xx"
      ],
      "js": [
        "contents.js"
      ],
      "run_at": "document_end",
      "all_frames": true
    }
  ]
}
```
## ネイティブアプリ設定のマニフェスト
```nativemanifest.json
{
    "name": "nativeexcute",
    "description": "NativeExcute",
    "path": "C:\\Users\\xxxx\\NativeMessagingExcute.exe",
    "type": "stdio",
    "allowed_origins": [
        "chrome-extension://xxxx拡張機能のIDxxxxx/"
    ]
}
```

## レジストリへの登録
エクスポートでレジストリへの登録する時は、下の所に空の2行が無いと上手くいかないようです。

```native_user.reg
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Edge\NativeMessagingHosts\nativeexcute]
@="C:\\Users\\ネイティブアプリ設定のマニフェスト保存場所のパス\\nativemanifest.json"


```

## マニフェストの設定など
拡張機能のマニフェストとネイティブアプリを呼び出すためのマニフェストの設定をどこでするかがややこしいので注意必要です。

下記サイトの下らへんに、エラー時に確認するポイントがあるので、その当たりも参考にする。
https://learn.microsoft.com/ja-jp/microsoft-edge/extensions-chromium/developer-guide/native-messaging?tabs=v3%2Cwindows

# つくったネイティブアプリ
.net コンソールアプリでつくりました。
主とした処理は、拡張機能から渡された値で`Process.Start`するだけです。
こちらに置いています。

https://github.com/msmsrep/NativeMessagingExcuteConsole



# 参考
- [ネイティブ メッセージング](https://learn.microsoft.com/ja-jp/microsoft-edge/extensions-chromium/developer-guide/native-messaging?tabs=v3%2Cwindows)
- [Native Messaging を使い、ブラウザ拡張でプロセス間通信を行う方法](https://tech.techtouch.jp/entry/browser-extension-interprocess-communication-using-native-messaging)
- [Chrome拡張機能とローカルアプリでプロセス間通信](https://dev.classmethod.jp/articles/chrome-native-message/)
- [【Google Chrome】NativeMessagingを使って拡張機能とC#クライアントアプリとで通信してみた](https://www.doraxdora.com/2022/01/22/post-17258/)
- [Lyre](https://github.com/alexwiese/Lyre)