多個 X11 伺服器(Xephyr、Xpra 等)之間共用剪貼簿

多個 X11 伺服器(Xephyr、Xpra 等)之間共用剪貼簿

我計劃運行有潛在危險的應用程式(瀏覽器等)在一台單獨的 X 伺服器上,但由於每個伺服器都有自己的剪貼簿,因此不可能將連結/文字從一個視窗複製到另一個視窗。

大多數文章建議使用 xclip 和其他類似實用程式的腳本來執行此操作。

但如何正確地建立一個通用剪貼簿以免意外建立新漏洞?

答案1

注意:更新答案以反映策略的變化 - 我不是在伺服器/容器上運行 Xephyr,而是在主機/主要使用環境上運行它。原因是在伺服器/容器上運行 Xephyr 就像在內門而不是前門上加鎖 - 不良行為者會繞過內門並直接透過 X 管道遠端套接字存取剪貼簿。

面對同樣的剪貼簿漏洞問題,我透過在主機(我的個人工作空間)上執行 Xephyr,並將 X 從容器上的伺服器轉送到本地 Xephyr 來解決這個問題。

Xephyr 在顯示器“:2”上運行,而我的個人工作區視窗和瀏覽器在預設顯示器“:0”上運行。這兩個顯示器不共用剪貼簿 - 每個顯示器都有自己的剪貼簿。這是防止在顯示器「:0」上窺探我的個人工作區剪貼簿的唯一方法。然後我設定了熱鍵(例如功能鍵),一個用於將剪貼簿內容從“:0”傳輸到“:2”,另一個用於“:2”到“:0”,因此允許完全控制。

在 shell 腳本中,程式碼可能如下所示

xsel --display :0 --clipboard -o |  xsel --display :2 --clipboard -i

儘管我使用的是 javascript,如本文底部所示。

啟動 X 轉送的 Shell 腳本可能如下所示

Xephyr <args> :2
DISPLAY=:2 ssh -X -R 44713:localhost:4713 user@container <<EOF
DISPLAY=:10 PULSE_SERVER=tcp:localhost:44713 openbox --startup firefox
EOF

雖然我使用的是 javascript 程式來做到這一點。

下面是在 ':0' 和 ":2" 之間複製的 javascript 程式碼,透過熱鍵映射到該程式碼。您可以看到它彈出一個臨時訊息框以確認其有效。

#!/usr/bin/env node
`strict`;
const child_process = require('child_process');

// TODO: write unviewable error messasges to system log

function notifySend(title, msg){
  title = title.replace(/"/g, '\\"');
  msg = msg.replace(/"/g, '\\"');
  //msg = msg.replace(/'/g, '\\'')
  try {
    child_process.execSync(`notify-send "${title}" "${msg}"`);
  } catch(e) {
    console.log(`system call "notify-send" failed with ${e.message}`);
  }
}

async function clipXfer(fromDispNum,toDispNum){
  var clipValue;
  let cmd1 = `xsel --display :${fromDispNum} --clipboard --output`;
  let cmd2 = `xsel --display :${toDispNum} --clipboard --input`;
  try {
    clipValue = child_process.execSync(cmd1, { encoding: 'utf-8' });
  } catch(e) {
    throw Error(`Display ${fromDispNum} clipboard is empty`);
  }
  await new Promise((resolve, reject)=>{        
    // eslint-disable-next-line no-unused-vars
    var proc = child_process.exec(cmd2, (error, stdout, stderr) => {
      //if (stdout) console.log(stdout);
      //if (stderr) console.log(stderr);
      if (error) {
        reject(Error(`${error.message}`));
      }
      resolve();
    });
    if (!proc.stdin.write(clipValue))
      reject(Error('clipToCont(), pipe write failed'));
    proc.stdin.end();
  });                    
}


async function main()
{
  let argOff=2;
  if (process.argv.length-argOff<2)
    throw Error('clip-xfer requires two arguments: fromDispNum, toDispNum');
  let fromDispNum = process.argv[argOff];
  let toDispNum = process.argv[argOff+1];
  argOff+=2;
  let f = (outcome)=>{
    notifySend("clipXfer",  `${fromDispNum} => ${toDispNum} ${outcome}`);
  }; 
  await clipXfer(fromDispNum,toDispNum)
    .then(f('SUCCESS'))
    .catch((e)=>{f(`FAILURE, ${e.message}`); throw e;});
}

//console.log(process.argv);
//console.log(process.env);
main()
  .then(()=>{process.exitCode=0;})
  .catch((e)=>{
    console.log(e);
    process.exitCode=1;
  });

答案2

我用剪輯同步。 98% 都有效。在 2% 中我正在這樣做:

顯示時:0 運行複製q。顯示:1次運行包裹岩。要同步我使用的剪貼簿

copyq add $(parcellite)

或向後

copyq read | parcellite -c

100%有效! :-)

相關內容