首页 > 解决方案 > 如何使电子通道更安全?

问题描述

以下是我通过 Electron 通道处理通信的方式:

preload.ts

contextBridge.exposeInMainWorld("myIpcRenderer", {
  invoke: (channel: Channel, ...args: any[]) =>
    callIpcRenderer("invoke", channel, ...args),
  send: (channel: Channel, ...args: any[]) =>
    callIpcRenderer("send", channel, ...args),
  on: (channel: Channel, ...args: any[]) =>
    callIpcRenderer("on", channel, ...args),
});

types.d.ts

interface MyIpcRenderer {
  invoke(channel: Channel.ReadFiles, ...args: any[]): Promise<ReadFileResult[]>;
}

MyIpcRenderer类型强制正确使用renderer.ts

const files = await window.myIpcRenderer.invoke(Channel.ReadFiles, [
  svgPath,
]);

但它不强制正确使用main.ts. ipcMain.handle指的是一种可以接受任何名称的通道并返回任何类型的承诺的电子方法。

ipcMain.handle(
  "anychannelnamegoes",
  async (_event, paths: string[]): Promise<any> => {
    ...
  }
);

如何重写我的代码以强制执行主要用法main.ts

标签: typescriptelectron

解决方案


我看到了两种方法来做到这一点。

第一种可能性是覆盖typings.d.ts文件中的电子库类型声明:

declare module 'electron' {
  export interface IpcMain extends NodeJS.EventEmitter {
    handle(
      channel: Channel,
      listener: (
        event: IpcMainInvokeEvent,
        ...args: any[]
      ) => Promise<void> | any
    ): void;
  }
}

考虑到这Channel是一个字符串文字 ( type Channel = 'channel1' | 'channel2'),您会得到关于'channel1'and的建议,但仍然允许'channel2'初始签名并且可以接受任何字符串。channel: string

我看到的第二种可能性是包装它,这将提供更好的类型安全性:

const myHandler = (
  channel: Channel,
  listener: (
    event: IpcMainInvokeEvent,
    ...args: any[]
  ) => Promise<void> | any
) => ipcMain.handle(channel, listener);

// only 'channel1' and 'channel2' would be accepted
myHandler('channel1', (event) => {});

我想键入当前使用扩展运算符...args: any[]声明的参数,您需要在两种情况下显式声明参数:

...
listener: (
  event: IpcMainInvokeEvent,
  arg1: string[],
  arg2: boolean,
  arg3: number
) => Promise<void> | any
...

推荐阅读