diff --git a/src/apps.js b/src/apps.js index 9339b8ad9..ca1858333 100644 --- a/src/apps.js +++ b/src/apps.js @@ -243,7 +243,10 @@ function validatePortBindings(portBindings, manifest) { if (!portBindings) return null; - for (let portName in portBindings) { + const tcpPorts = manifest.tcpPorts || { }; + const udpPorts = manifest.udpPorts || { }; + + for (const portName in portBindings) { if (!/^[a-zA-Z0-9_]+$/.test(portName)) return new BoxError(BoxError.BAD_FIELD, `${portName} is not a valid environment variable in portBindings`); const hostPort = portBindings[portName]; @@ -251,14 +254,11 @@ function validatePortBindings(portBindings, manifest) { if (RESERVED_PORTS.indexOf(hostPort) !== -1) return new BoxError(BoxError.BAD_FIELD, `Port ${hostPort} for ${portName} is reserved in portBindings`); if (RESERVED_PORT_RANGES.find(range => (hostPort >= range[0] && hostPort <= range[1]))) return new BoxError(BoxError.BAD_FIELD, `Port ${hostPort} for ${portName} is reserved in portBindings`); if (ALLOWED_PORTS.indexOf(hostPort) === -1 && (hostPort <= 1023 || hostPort > 65535)) return new BoxError(BoxError.BAD_FIELD, `${hostPort} for ${portName} is not in permitted range in portBindings`); - } - // it is OK if there is no 1-1 mapping between values in manifest.tcpPorts and portBindings. missing values implies - // that the user wants the service disabled - const tcpPorts = manifest.tcpPorts || { }; - const udpPorts = manifest.udpPorts || { }; - for (let portName in portBindings) { - if (!(portName in tcpPorts) && !(portName in udpPorts)) return new BoxError(BoxError.BAD_FIELD, `Invalid portBindings ${portName}`); + // it is OK if there is no 1-1 mapping between values in manifest.tcpPorts and portBindings. missing values implies the service is disabled + const portSpec = tcpPorts[portName] || udpPorts[portName]; + if (!portSpec) return new BoxError(BoxError.BAD_FIELD, `Invalid portBinding ${portName}`); + if (portSpec.readOnly && portSpec.defaultValue !== hostPort) return new BoxError(BoxError.BAD_FIELD, `portBinding ${portName} is readOnly and cannot have a different value that the default`); } return null;