openvibers/openvibe.host Commits

shots: hand the capture folder to ovcheck (#294)

OP OpenVibers committed 7 days ago · 36e0c22a3d · 1 file, +14 −1

ovhost shots --dry-run on the host failed with EACCES on targets.json: mkdtemp makes the folder root's own (0700)
and Chrome runs as ovcheck. Running as root, the folder, the targets file and the png folder now belong to the
capture account, still 0700; root reads the PNGs back, nobody else can.

Changes

ddiff --git a/lib/shots.js b/lib/shots.js
iindex cae9f51..cbffa5a 100644
---- a/lib/shots.js
++++ b/lib/shots.js
@@@ -18,7 +18,7 @@
* Only public pages are captured: the origins come from the inventory, and a page that is not a
* path of a public site is refused before Chrome starts.
*/
--const { spawn } = require('child_process');
++const { spawn, execFileSync } = require('child_process');
const crypto = require('crypto');
const fs = require('fs');
const os = require('os');
@@@ -74,6 +74,19 @@ function captureWithChrome(targets, { asUser = 'ovcheck', home = '/var/lib/ovche
const outDir = path.join(dir, 'png');
fs.mkdirSync(outDir, { recursive: true });
fs.writeFileSync(targetsFile, JSON.stringify(targets));
++ // Chrome runs as asUser, and mkdtemp made the folder root's own (0700): hand the folder to that account,
++ // still 0700, so it can read the targets and write the PNGs; root reads them back, nobody else can.
++ if (asUser && process.getuid && process.getuid() === 0) {
++ try {
++ const ids = (flag) => Number(String(execFileSync('id', [flag, asUser])).trim());
++ const uid = ids('-u'), gid = ids('-g');
++ for (const p of [dir, targetsFile, outDir]) fs.chownSync(p, uid, gid);
++ } catch (e) {
++ fs.rmSync(dir, { recursive: true, force: true });
++ resolve({ shots: [], error: `cannot hand the capture folder to ${asUser}: ${e.message}` });
++ return;
++ }
++ }
const argv = [SCRIPT, '--targets', targetsFile, '--out', outDir];
const child = asUser
? spawnFn('runuser', ['-u', asUser, '--', 'env', `HOME=${home || '/tmp'}`, process.execPath, ...argv], { stdio: ['ignore', 'pipe', 'pipe'] })