Electron + xmpp.js:如何调试 SSL 自签名错误消息?

Posted

技术标签:

【中文标题】Electron + xmpp.js:如何调试 SSL 自签名错误消息?【英文标题】:Electron + xmpp.js: How I can Debug SSL Self-signed error messages? 【发布时间】:2018-11-21 21:38:52 【问题描述】:

我正在使用 electron.js 和 xmpp.js 的组合来创建自己的客户端。我的主要项目由这两个文件组成:

助推电子开启:index.js:

const app,BrowserWindow,ipcMain,dialog=require('electron');
// const app=electron.app;
// const BrowserWindow=electron.BrowserWindow;

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup'))  // eslint-disable-line global-require
  app.quit();


// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is garbage collected.
let mainWindow;

const createWindow = () => 
  console.log("Message");
  // Create the browser window.
  mainWindow = new BrowserWindow();

  // and load the index.html of the app.
  mainWindow.loadURL(`file://$__dirname/ui/index.html`);
  var env = process.env.NODE_ENV || 'production';

  if(env==='dev')
    // Open the DevTools.
    mainWindow.webContents.openDevTools();
  

  // Emitted when the window is closed.
  mainWindow.on('closed', () => 
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  );

  mainWindow.maximize();

  const xmpp=require('./xmpp.js');
  console.log(xmpp)
  xmpp.xmppCli(mainWindow,ipcMain,dialog);
;

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);

// Quit when all windows are closed.
app.on('window-all-closed', () => 
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') 
    app.quit();
  
);

app.on('activate', () => 
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) 
    createWindow();
  
);

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.

并用这个文件处理它xmpp.js:

const client, xml, jid = require('@xmpp/client')

var clientInstance=null;

console.log('xmpp.js loaded')

const initXmpp= function(xmpp)

  xmpp.on('error', err => 
    console.error("Error occured",err.toString())
    dialog.showErrorBox('Internal Error',err.toString())
  )

  xmpp.on('offline', () => 
    console.log('????', 'offline')
  )

  xmpp.on('online', async address => 
    dialog.showMessageBox('type':'info','message':"Online as:"+address.toString())
  )

  xmpp.on('stanza', stanza => 
    console.log('⮈', stanza.toString())
    xmpp.stop()
  )

  process.on('unhandledRejection', function (reason, p) 
    console.log('Possibly Unhandled Rejection at: Promise ', p, ' reason: ', reason)
  )

  xmpp.start()


module.exports.xmppCli=function(mainWindow,ipcMain,dialog)


  ipcMain.on('login',(event,params)=>
    let jidVal=jid(params.username);
    params.server="xmpp://"+params.server
    console.log(jidVal.getLocal(),jidVal.getDomain(),params.server)

    if(!clientInstance)
      console.log("Client Works");
      try
          clientInstance=new client(
            'service':params.server,
            'domain': jidVal.getDomain(),
            'username':jidVal.getLocal(),
            'password':params.password,
          )
          initXmpp(clientInstance)
       catch(e) 
        console.error('Internal Error',e.message)
        console.error(e.stack)
        clientInstance=null;
      
    

  );

我的用户界面也由index.html组成:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Login Page</title>

    <link rel="stylesheet" href="../../node_modules/bootstrap/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="../../node_modules/roboto-fontface/css/roboto/roboto-fontface.css">
    <style>
      html, body, .container-fluid 
          height: 100%;
          font-family: 'Roboto', sans-serif;
      

      #form_wrapper
          border:1px solid;
          border-radius: 10px;
      
    </style>

    <script>window.$ = window.jQuery = require('../../node_modules/jquery/dist/jquery.min.js');</script>
    <script src="../../node_modules/jquery/dist/jquery.min.js"></script>
    <script src="./index_renderer.js"></script>
  </head>
  <body class="bg-secondary">
    <div class="container-fluid d-flex justify-content-center align-items-center">
      <div id="form_wrapper" class="p-2" style="background-color:white;">
          <h1 class="text-center">XMPP KEY AGREEMENT CLI</h1>
          <form id="loginForm">
            <div class="form-group">
              <label for="server">XMPP Server</label>
              <input id="server" class="form-control" type="text" name="server" placeholder="eg. example.com" required>
            </div>
            <div class="form-group">
              <label for="username">Username</label>
              <input id="username" class="form-control" type="text" name="username" placeholder="eg. user@example.com" required>
            </div>
            <div class="form-group">
              <label for="password">Password</label>
              <input id="password" class="form-control" type="text" name="password" placeholder="Type your password here" required>
            </div>
            <button type="submit" class="btn btn-primary btn-lg btn-block">Login</button>
          </form>
      </div>
    </div>
  </body>
</html>

使用以下渲染器:

$(document).ready(function()
  const ipcRenderer = require('electron').ipcRenderer;

  $("#loginForm").on('submit',function(e)
    e.preventDefault();
    console.log("Form Submitted");
    //https://***.com/a/29000408/4706711
    let data=$(this).serializeArray().reduce(function(a, x)  a[x.name] = x.value; return a; , );
    ipcRenderer.send('login',data)
  )

)

但我的问题是,当我使用自签名证书启动自己的本地 opefireserver 时。因此,我得到一个神秘的错误,显示如下:

所以我的问题是:

如何调试这些类型的错误?我的意思是我找不到这个错误的位置。 如何手动告诉 electron 或 xmpp.js 手动接受自签名证书>

我试图通过更改手动找出这个错误是在哪里产生的:

  xmpp.on('error', err => 
    console.error("Error occured",err.toString())
    dialog.showErrorBox('Internal Error',err.toString())
  )

进入这个:

  xmpp.on('error', err => 
    console.error("Error occured",err.toString())
  )

仍然出现奇怪的错误。

【问题讨论】:

【参考方案1】:

@xmpp/client 库在发生连接错误时似乎缺少 api 调用,如下例所示:

const client, xml, jid = require('@xmpp/client')

const initXmpp=function(xmpp)

  xmpp.on('error', err => 
    console.error("Error occured",err.toString())
    // dialog.showErrorBox('Internal Error',err.toString())
  )

  xmpp.on('offline', () => 
    console.log('?', 'offline')
  )

  xmpp.on('online', async address => 
    dialog.showMessageBox('type':'info','message':"Online as:"+address.toString())
  )

  xmpp.on('stanza', stanza => 
    console.log('⮈', stanza.toString())
    xmpp.stop()
  )

  process.on('unhandledRejection', function (reason, p) 
    console.error('Possibly Unhandled Rejection at: Promise ', p, ' reason: ', reason)
  )

  try
    xmpp.start()
   catch(e) 
    console.error(e.message)
  


try
  clientInstance=new client(
    'service':"xmpp://0.0.0.0:5222",
    'domain': "example.com",
    'username':"admin",
    'password':"admin",
  );

  initXmpp(clientInstance);
 catch(e) 
  console.error(e);

我收到以下错误:

 events.js:183
      throw er; // Unhandled 'error' event
      ^
Error: self signed certificate
    at TLSSocket.<anonymous> (_tls_wrap.js:1105:38)
    at emitNone (events.js:106:13)
    at TLSSocket.emit (events.js:208:7)
    at TLSSocket._finishInit (_tls_wrap.js:639:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:469:38)

并且没有提供处理它的方法,那是因为 SSL/TLS 连接是由 nodejs 本身处理的,因此唯一的解决方案可以在这个 gthub answer 上找到。

基于上面提到的实际结合NODE_ENV环境变量的方案,我在index.js上放置了如下代码sn-p:

if(env==='dev' || env=='debug')
  process.env.NODE_TLS_REJECT_UNAUTHORIZED=0;

另外,如果使用this,我建议分叉并修改它以使用最新版本的ubuntu(甚至更稳定的docker镜像)和更高版本的openfire,例如this guy。

【讨论】:

以上是关于Electron + xmpp.js:如何调试 SSL 自签名错误消息?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Visual Studio Code 中的 Electron 和 Angular 调试应用程序?

如何在 Visual Studio 中使用 breakpad 符号调试 Electron shell?

使用 VSCode 调试 Electron 主进程代码

Electron 主进程调试

如何使用 IntelliJ 或 WebStorm 调试电子应用程序?

Visual Studio Code调试electron主进程