Auto-merge for PR #641 via VersionBot

Convert errors and iptables modules to typescript
This commit is contained in:
resin-io-versionbot[bot] 2018-06-11 10:21:08 +00:00 committed by GitHub
commit dab233f04b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 57 deletions

View File

@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
This project adheres to [Semantic Versioning](http://semver.org/).
## v7.10.1 - 2018-06-11
* Convert iptables module to typescript #641 [Cameron Diver]
* Convert errors module to typescript #641 [Cameron Diver]
## v7.10.0 - 2018-06-06
* Move config backend code out to classes which implement a common base #672 [Cameron Diver]

View File

@ -1,7 +1,7 @@
{
"name": "resin-supervisor",
"description": "This is resin.io's Supervisor, a program that runs on IoT devices and has the task of running user Apps (which are Docker containers), and updating them as Resin's API informs it to.",
"version": "7.10.0",
"version": "7.10.1",
"license": "Apache-2.0",
"repository": {
"type": "git",
@ -16,16 +16,17 @@
"coverage": "istanbul report text && istanbul report html"
},
"dependencies": {
"@types/lodash": "^4.14.108",
"@types/mz": "0.0.32",
"mkfifo": "^0.1.5",
"mz": "^2.7.0",
"sqlite3": "^3.1.0"
},
"engines": {
"node": "^6.13.1"
},
"devDependencies": {
"@types/bluebird": "^3.5.20",
"@types/lodash": "^4.14.109",
"@types/mz": "0.0.32",
"@types/node": "^10.3.1",
"JSONStream": "^1.1.2",
"blinking": "~0.0.2",
"bluebird": "^3.5.0",
@ -53,6 +54,7 @@
"mkdirp": "^0.5.1",
"mocha": "^5.1.1",
"mochainon": "^2.0.0",
"mz": "^2.7.0",
"network-checker": "~0.0.5",
"node-loader": "^0.6.0",
"null-loader": "^0.1.1",

View File

@ -1,6 +0,0 @@
{ checkInt } = require './validation'
exports.NotFoundError = (err) -> checkInt(err.statusCode) is 404
exports.ENOENT = (err) -> err.code is 'ENOENT'
exports.EEXIST = (err) -> err.code is 'EEXIST'
exports.UnitNotLoadedError = (err) -> err[0]?.endsWith?('not loaded.')

19
src/lib/errors.ts Normal file
View File

@ -0,0 +1,19 @@
import { endsWith } from 'lodash';
import { checkInt } from './validation';
export function NotFoundError(err: { statusCode?: string }): boolean {
return checkInt(err.statusCode) === 404;
}
export function ENOENT(err: { code: string, [key: string]: any }): boolean {
return err.code === 'ENOENT';
}
export function EEXISTS(err: { code: string, [key: string]: any }): boolean {
return err.code === 'EEXISTS';
}
export function UnitNotLoadedError(err: string[]): boolean {
return endsWith(err[0], 'not loaded.');
}

View File

@ -1,25 +0,0 @@
Promise = require 'bluebird'
childProcess = Promise.promisifyAll(require('child_process'))
clearAndAppendIptablesRule = (rule) ->
childProcess.execAsync("iptables -D #{rule}")
.catchReturn()
.then ->
childProcess.execAsync("iptables -A #{rule}")
clearAndInsertIptablesRule = (rule) ->
childProcess.execAsync("iptables -D #{rule}")
.catchReturn()
.then ->
childProcess.execAsync("iptables -I #{rule}")
exports.rejectOnAllInterfacesExcept = (allowedInterfaces, port) ->
# We delete each rule and create it again to ensure ordering (all ACCEPTs before the REJECT/DROP).
# This is especially important after a supervisor update.
Promise.each allowedInterfaces, (iface) ->
clearAndInsertIptablesRule("INPUT -p tcp --dport #{port} -i #{iface} -j ACCEPT")
.then ->
clearAndAppendIptablesRule("INPUT -p tcp --dport #{port} -j REJECT")
.catch ->
# On systems without REJECT support, fall back to DROP
clearAndAppendIptablesRule("INPUT -p tcp --dport #{port} -j DROP")

32
src/lib/iptables.ts Normal file
View File

@ -0,0 +1,32 @@
import * as Promise from 'bluebird';
import * as childProcess from 'child_process';
// The following is exported so that we stub it in the tests
export const execAsync = Promise.promisify(childProcess.exec);
function clearAndAppendIptablesRule(rule: string): Promise<void> {
return execAsync(`iptables -D ${rule}`)
.catchReturn(null)
.then(() => execAsync(`iptables -A ${rule}`))
.return();
}
function clearAndInsertIptablesRule(rule: string): Promise<void> {
return execAsync(`iptables -D ${rule}`)
.catchReturn(null)
.then(() => execAsync(`iptables -I ${rule}`))
.return();
}
export function rejectOnAllInterfacesExcept(
allowedInterfaces: string[],
port: number,
): Promise<void> {
// We delete each rule and create it again to ensure ordering (all ACCEPTs before the REJECT/DROP).
// This is especially important after a supervisor update.
return Promise.each(allowedInterfaces, (iface) => clearAndInsertIptablesRule(`INPUT -p tcp --dport ${port} -i ${iface} -j ACCEPT`))
.then(() => clearAndAppendIptablesRule(`INPUT -p tcp --dport ${port} -j REJECT`))
// On systems without REJECT support, fall back to DROP
.catch(() => clearAndAppendIptablesRule(`INPUT -p tcp --dport ${port} -j DROP`))
.return();
}

View File

@ -1,43 +1,41 @@
Promise = require 'bluebird'
iptables = require '../src/lib/iptables'
childProcess = require('child_process')
m = require 'mochainon'
{ stub } = m.sinon
{ expect } = m.chai
describe 'iptables', ->
it 'calls iptables to delete and recreate rules to block a port', ->
stub(childProcess, 'execAsync').returns(Promise.resolve())
stub(iptables, 'execAsync').returns(Promise.resolve())
iptables.rejectOnAllInterfacesExcept(['foo', 'bar'], 42)
.then ->
expect(childProcess.execAsync.callCount).to.equal(6)
expect(childProcess.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -i foo -j ACCEPT')
expect(childProcess.execAsync).to.be.calledWith('iptables -I INPUT -p tcp --dport 42 -i foo -j ACCEPT')
expect(childProcess.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -i bar -j ACCEPT')
expect(childProcess.execAsync).to.be.calledWith('iptables -I INPUT -p tcp --dport 42 -i bar -j ACCEPT')
expect(childProcess.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -j REJECT')
expect(childProcess.execAsync).to.be.calledWith('iptables -A INPUT -p tcp --dport 42 -j REJECT')
expect(iptables.execAsync.callCount).to.equal(6)
expect(iptables.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -i foo -j ACCEPT')
expect(iptables.execAsync).to.be.calledWith('iptables -I INPUT -p tcp --dport 42 -i foo -j ACCEPT')
expect(iptables.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -i bar -j ACCEPT')
expect(iptables.execAsync).to.be.calledWith('iptables -I INPUT -p tcp --dport 42 -i bar -j ACCEPT')
expect(iptables.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -j REJECT')
expect(iptables.execAsync).to.be.calledWith('iptables -A INPUT -p tcp --dport 42 -j REJECT')
.then ->
childProcess.execAsync.restore()
iptables.execAsync.restore()
it "falls back to blocking the port with DROP if there's no REJECT support", ->
stub(childProcess, 'execAsync').callsFake (cmd) ->
stub(iptables, 'execAsync').callsFake (cmd) ->
if /REJECT$/.test(cmd)
Promise.reject()
else
Promise.resolve()
iptables.rejectOnAllInterfacesExcept(['foo', 'bar'], 42)
.then ->
expect(childProcess.execAsync.callCount).to.equal(8)
expect(childProcess.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -i foo -j ACCEPT')
expect(childProcess.execAsync).to.be.calledWith('iptables -I INPUT -p tcp --dport 42 -i foo -j ACCEPT')
expect(childProcess.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -i bar -j ACCEPT')
expect(childProcess.execAsync).to.be.calledWith('iptables -I INPUT -p tcp --dport 42 -i bar -j ACCEPT')
expect(childProcess.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -j REJECT')
expect(childProcess.execAsync).to.be.calledWith('iptables -A INPUT -p tcp --dport 42 -j REJECT')
expect(childProcess.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -j DROP')
expect(childProcess.execAsync).to.be.calledWith('iptables -A INPUT -p tcp --dport 42 -j DROP')
expect(iptables.execAsync.callCount).to.equal(8)
expect(iptables.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -i foo -j ACCEPT')
expect(iptables.execAsync).to.be.calledWith('iptables -I INPUT -p tcp --dport 42 -i foo -j ACCEPT')
expect(iptables.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -i bar -j ACCEPT')
expect(iptables.execAsync).to.be.calledWith('iptables -I INPUT -p tcp --dport 42 -i bar -j ACCEPT')
expect(iptables.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -j REJECT')
expect(iptables.execAsync).to.be.calledWith('iptables -A INPUT -p tcp --dport 42 -j REJECT')
expect(iptables.execAsync).to.be.calledWith('iptables -D INPUT -p tcp --dport 42 -j DROP')
expect(iptables.execAsync).to.be.calledWith('iptables -A INPUT -p tcp --dport 42 -j DROP')
.then ->
childProcess.execAsync.restore()
iptables.execAsync.restore()