javascript - Electron - 在打开保存对话框之前写入文件

标签 javascript node.js vue.js electron

我正在使用 Electron 开发应用程序。完成一些加密操作后,我需要向用户显示一个对话框来保存文件。我想给文件的文件名是一个随机哈希,但我也没有成功。我正在尝试使用此代码,但不会保存文件。我该如何解决这个问题?

const downloadPath = app.getPath('downloads')

ipcMain.on('encryptFiles', (event, data) => {
  let output = [];
  const password = data.password;
  data.files.forEach( (file) => {
    const buffer = fs.readFileSync(file.path);
    const dataURI = dauria.getBase64DataURI(buffer, file.type);
    const encrypted = CryptoJS.AES.encrypt(dataURI, password).toString();
    output.push(encrypted);
  })
  const filename = hash.createHash('md5').toString('hex');
  console.log(filename)
  const response = output.join(' :: ');
  dialog.showSaveDialog({title: 'Save encrypted file', defaultPath: downloadPath }, () => {
    fs.writeFile(`${filename}.mfs`, response, (err) => console.log(err) )  
  })
})

最佳答案

您遇到的问题是由 Electron 的 UI 函数的异步性质引起的:它们不接受回调函数,而是返回 Promise。因此,您不必传入回调函数,而是处理 Promise 的解析。请注意,这仅适用于 Electron >= 版本 6。但是,如果您运行旧版本的 Electron,您的代码将是正确的——但是您应该真正更新到较新的版本(Electron v6 是一年多前发布的) .
像下面这样调整您的代码可以成为解决问题的起点。但是,由于您没有说明如何生成哈希(hash.createHash 来自哪里?;您是否忘记声明/导入 hash ?;您是否忘记传递任何消息字符串?;您是否使用 hash?作为 NodeJS 的 crypto 模块的别名?),(此时)无法调试为什么您没有从 console.log (filename) 获得任何输出(我假设您的意思是“在代码中,不会创建随机文件名”)。一旦您提供有关此问题的更多详细信息,我很乐意相应地更新此答案。
至于默认文件名:根据 Electron documentation ,您可以将文件路径传递到 dialog.showSaveDialog ()为用户提供默认文件名。
您使用的文件类型扩展名实际上也应该与文件扩展名一起传递到保存对话框中。同样将此文件扩展名作为过滤器传递到对话框中将阻止用户选择任何其他文件类型,这最终也是您当前正在执行的操作,方法是将其附加到文件名中。
此外,您可以使用 CryptoJS 生成文件名:给定一些任意字符串,这实际上可能是随机字节,您可以这样做:filename = CryptoJS.MD5 ('some text here') + '.mfs';但是,请记住明智地选择输入字符串。 MD5 已被破坏,因此不应再用于存储 secret 信息——使用任何对您存储的文件加密至关重要的已知信息(例如 data.password )本质上是不安全的。互联网上有一些关于如何在 JavaScript 中创建随机字符串的好例子,还有 this answer。在这里。
考虑到所有这些问题,最终可能会得到以下代码:

const downloadPath = app.getPath('downloads'),
      path = require('path');

ipcMain.on('encryptFiles', (event, data) => {
  let output = [];
  const password = data.password;

  data.files.forEach((file) => {
    const buffer = fs.readFileSync(file.path);
    const dataURI = dauria.getBase64DataURI(buffer, file.type);
    const encrypted = CryptoJS.AES.encrypt(dataURI, password).toString();
    output.push(encrypted);
  })

  // not working:
  // const filename = hash.createHash('md5').toString('hex') + '.mfs';

  // alternative requiring more research on your end
  const filename = CryptoJS.MD5('replace me with some random bytes') + '.mfs';
  console.log(filename);

  const response = output.join(' :: ');
  dialog.showSaveDialog(
    {
      title: 'Save encrypted file',
      defaultPath: path.format ({ dir: downloadPath, base: filename }), // construct a proper path
      filters: [{ name: 'Encrypted File (*.mfs)', extensions: ['mfs'] }] // filter the possible files
    }
  ).then ((result) => {
    if (result.canceled) return; // discard the result altogether; user has clicked "cancel"
    else {
      var filePath = result.filePath;
      if (!filePath.endsWith('.mfs')) {
        // This is an additional safety check which should not actually trigger.
        // However, generally appending a file extension to a filename is not a
        // good idea, as they would be (possibly) doubled without this check.
        filePath += '.mfs';
      }
      fs.writeFile(filePath, response, (err) => console.log(err) )  
    }
  }).catch ((err) => {
    console.log (err);
  });
})

关于javascript - Electron - 在打开保存对话框之前写入文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65168529/

相关文章:

javascript - Javascript 文字对象中的私有(private)变量

javascript - 如何解决 'Redirect has been blocked by CORS policy: No ' Access-Control-Allow-Origin' header'?

node.js - 使用 Node.js 的 Express 进行 SEO

javascript - 如何在 vuex 中将 2 个参数传递给 getter?

vue.js - 从 Vuejs 中的动态表单获取所有输入值

javascript - MongoDB 文档已添加但未显示在网站上(无需刷新)

Javascript 范围和调用函数

javascript - 我的事件监听器只触发一次,甚至运行代码都没有错误?

node.js - 设置 mongojs 集合的写入关注

api - 支付宝 API : How do I update a subscription's credit card?