Add option for socket permissions

This allows configuring the group and mode of the unix socket after it
has been created to allow reverse proxies to access it. Fixes #317.

I decided to call `chown` and `chgrp` directly to change the owner and
group (the former will almost definitely not be called; only root can
chown a file to another user, and you are not running codimd as root. It
is included for consistency).

The nodejs chown/chgrp functions only accepts uid and gid, not the names
of the user or group. The standard way to convert a group name into a gid
is the `uid-number` package. The way this package works is that

1. It spawns a new nodejs process
2. The new nodejs process calls nodejs' setgid function, which *does*
   accept both the group name and gid
3. It then calls getuid to retrieve the uid of the process, and returns
   it to the parent process via stdout.

While this *works*, it is hacky, and if we are spawning a process
anyway, might as well call `chgrp` directly.

This does not update the documentation because we are merging into
release/2.0.x but master reworks the configuration section of the
documentation, so there will be a conflict when we merge anyway.

Signed-off-by: Dexter Chua <dalcde@yahoo.com.hk>
This commit is contained in:
Dexter Chua 2020-06-20 22:37:31 +08:00
parent 77fbfa33a1
commit f2aba67374
3 changed files with 25 additions and 1 deletions

View file

@ -6,6 +6,7 @@ import cookieParser from 'cookie-parser'
import ejs from 'ejs' import ejs from 'ejs'
import express from 'express' import express from 'express'
import session from 'express-session' import session from 'express-session'
import childProcess from 'child_process'
import helmet from 'helmet' import helmet from 'helmet'
import http from 'http' import http from 'http'
import https from 'https' import https from 'https'
@ -255,10 +256,23 @@ function startListen (): void {
realtime.maintenance = false realtime.maintenance = false
} }
const unixCallback = function (): void {
const throwErr = function (err): void { if (err) throw err }
if (config.socket.owner !== undefined) {
childProcess.spawn('chown', [config.socket.owner, config.path]).on('error', throwErr)
}
if (config.socket.group !== undefined) {
childProcess.spawn('chgrp', [config.socket.group, config.path]).on('error', throwErr)
}
if (config.socket.mode !== undefined) {
fs.chmod(config.path, config.socket.mode, throwErr)
}
listenCallback()
}
// use unix domain socket if 'path' is specified // use unix domain socket if 'path' is specified
if (config.path) { if (config.path) {
address = config.path address = config.path
server.listen(config.path, listenCallback) server.listen(config.path, unixCallback)
} else { } else {
address = config.host + ':' + config.port address = config.host + ':' + config.port
server.listen(config.port, config.host, listenCallback) server.listen(config.port, config.host, listenCallback)

View file

@ -8,6 +8,11 @@ export const defaultConfig: Config = {
urlPath: '', urlPath: '',
host: '0.0.0.0', host: '0.0.0.0',
port: 3000, port: 3000,
socket: {
group: undefined,
owner: undefined,
mode: undefined
},
loglevel: 'info', loglevel: 'info',
urlAddPort: false, urlAddPort: false,
allowOrigin: ['localhost'], allowOrigin: ['localhost'],

View file

@ -7,6 +7,11 @@ export const environment = {
host: process.env.CMD_HOST, host: process.env.CMD_HOST,
port: toIntegerConfig(process.env.CMD_PORT), port: toIntegerConfig(process.env.CMD_PORT),
path: process.env.CMD_PATH, path: process.env.CMD_PATH,
socket: {
group: process.env.CMD_SOCKET_GROUP,
owner: process.env.CMD_SOCKET_OWNER,
mode: process.env.CMD_SOCKET_MODE
},
loglevel: process.env.CMD_LOGLEVEL, loglevel: process.env.CMD_LOGLEVEL,
urlAddPort: toBooleanConfig(process.env.CMD_URL_ADDPORT), urlAddPort: toBooleanConfig(process.env.CMD_URL_ADDPORT),
useSSL: toBooleanConfig(process.env.CMD_USESSL), useSSL: toBooleanConfig(process.env.CMD_USESSL),