Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e74f7221b5 | ||
|
|
f4fc3a90bc | ||
|
|
df3aa6e165 | ||
|
|
986bcd7971 | ||
|
|
7f3ea431a1 | ||
|
|
dae0252857 | ||
|
|
33b8e5272c | ||
|
|
21e73757ac | ||
|
|
bcb5d3b7ef | ||
|
|
d2f3f460b2 | ||
|
|
e06fe6f5a3 | ||
|
|
fb9dabfe6b | ||
|
|
0e0cd8fed5 | ||
|
|
8959e1782f | ||
|
|
33151105e0 | ||
|
|
77b40eb9ed | ||
|
|
075dfd0aa7 | ||
|
|
5cf6b1c218 | ||
|
|
6527746a91 | ||
|
|
020ca9c6b3 | ||
|
|
8c7831480b | ||
|
|
e399dfd8e4 | ||
|
|
be83c7148d | ||
|
|
ce187e8675 | ||
|
|
f13ede4ba7 | ||
|
|
fb061ed419 | ||
|
|
b4a377f269 | ||
|
|
de6f37aa64 | ||
|
|
32219577b8 | ||
|
|
abc7329a71 | ||
|
|
675942e967 | ||
|
|
5b20cd501e | ||
|
|
b6aaf4d7cf | ||
|
|
972e232559 | ||
|
|
851a91b1a0 | ||
|
|
6a068dc430 | ||
|
|
2cdfcf60fe | ||
|
|
cbf8263033 |
@@ -1,7 +1,7 @@
|
||||
defaults: &defaults
|
||||
working_directory: /go/src/moul.io/sshportal
|
||||
docker:
|
||||
- image: circleci/golang:1.12.6
|
||||
- image: circleci/golang:1.14.4
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
|
||||
@@ -16,18 +16,6 @@ install_retry: &install_retry
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
go.build:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- *install_retry
|
||||
- run: /tmp/retry -m 3 go mod download
|
||||
- run: /tmp/retry -m 3 go mod vendor
|
||||
- run: /tmp/retry -m 3 make install
|
||||
- run: GO111MODULE=off /tmp/retry -m 3 go test -v ./...
|
||||
- run: /tmp/retry -m 3 curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.12.2
|
||||
- run: PATH=$PATH:$(pwd)/bin /tmp/retry -m 3 make lint
|
||||
|
||||
docker.integration:
|
||||
<<: *defaults
|
||||
steps:
|
||||
@@ -48,6 +36,4 @@ workflows:
|
||||
version: 2
|
||||
build_and_integration:
|
||||
jobs:
|
||||
- go.build
|
||||
- docker.integration
|
||||
# requires: docker.build?
|
||||
|
||||
3
renovate.json → .github/renovate.json
vendored
3
renovate.json → .github/renovate.json
vendored
@@ -2,5 +2,6 @@
|
||||
"extends": [
|
||||
"config:base"
|
||||
],
|
||||
"groupName": "all"
|
||||
"groupName": "all",
|
||||
"gomodTidy": true
|
||||
}
|
||||
88
.github/workflows/ci.yml
vendored
Normal file
88
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
docker-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build the Docker image
|
||||
run: docker build . --file Dockerfile
|
||||
golangci-lint:
|
||||
name: golangci-lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: lint
|
||||
uses: golangci/golangci-lint-action@v0.1.7
|
||||
with:
|
||||
version: v1.26
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tests-on-windows:
|
||||
needs: golangci-lint # run after golangci-lint action to not produce duplicated errors
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
golang:
|
||||
#- 1.13
|
||||
- 1.14
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.golang }}
|
||||
- name: Run tests on Windows
|
||||
run: make.exe unittest
|
||||
continue-on-error: true
|
||||
tests-on-mac:
|
||||
needs: golangci-lint # run after golangci-lint action to not produce duplicated errors
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
golang:
|
||||
- 1.14
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.golang }}
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ matrix.golang }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-${{ matrix.golang }}-
|
||||
- name: Run tests on Unix-like operating systems
|
||||
run: make unittest
|
||||
tests-on-linux:
|
||||
needs: golangci-lint # run after golangci-lint action to not produce duplicated errors
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
golang:
|
||||
- 1.11
|
||||
- 1.12
|
||||
- 1.13
|
||||
- 1.14
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.golang }}
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ matrix.golang }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-${{ matrix.golang }}-
|
||||
- name: Run tests on Unix-like operating systems
|
||||
run: make unittest
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
coverage.txt
|
||||
dist/
|
||||
*~
|
||||
*#
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
run:
|
||||
deadline: 1m
|
||||
tests: false
|
||||
#skip-files:
|
||||
# - ".*\\.gen\\.go"
|
||||
skip-files:
|
||||
- "testing.go"
|
||||
- ".*\\.pb\\.go"
|
||||
- ".*\\.gen\\.go"
|
||||
|
||||
linters-settings:
|
||||
golint:
|
||||
@@ -18,17 +20,36 @@ linters-settings:
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- goconst
|
||||
- misspell
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- misspell
|
||||
- structcheck
|
||||
- depguard
|
||||
- dogsled
|
||||
#- dupl
|
||||
- errcheck
|
||||
- unused
|
||||
- varcheck
|
||||
- staticcheck
|
||||
- unconvert
|
||||
#- funlen
|
||||
- gochecknoinits
|
||||
#- gocognit
|
||||
- goconst
|
||||
- gocritic
|
||||
#- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
- golint
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
#- maligned
|
||||
- misspell
|
||||
- nakedret
|
||||
- prealloc
|
||||
- scopelint
|
||||
- staticcheck
|
||||
- structcheck
|
||||
#- stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
- whitespace
|
||||
|
||||
29
AUTHORS
Normal file
29
AUTHORS
Normal file
@@ -0,0 +1,29 @@
|
||||
# This file lists all individuals having contributed content to the repository.
|
||||
# For how it is generated, see 'https://github.com/moul/rules.mk'
|
||||
|
||||
ahh <ahamidullah@gmail.com>
|
||||
Alen Masic <alenn.masic@gmail.com>
|
||||
Alexander Turner <me@alexturner.co>
|
||||
bozzo <bozzo@users.noreply.github.com>
|
||||
fossabot <badges@fossa.io>
|
||||
Jean-Louis Férey <jeanlouis.ferey@orange.com>
|
||||
Jess <jessachandler@gmail.com>
|
||||
Jonathan Lestrelin <jonathan.lestrelin@gmail.com>
|
||||
Julien Dessaux <julien.dessaux@adyxax.org>
|
||||
Manfred Touron <94029+moul@users.noreply.github.com>
|
||||
Manfred Touron <m@42.am>
|
||||
Manuel <manuel.sabban@nbs-system.com>
|
||||
Manuel Sabban <manu@sabban.eu>
|
||||
Manuel Sabban <msa@nbs-system.com>
|
||||
Mathieu Pasquet <mathieu.pasquet@alterway.fr>
|
||||
Mikael Rapp <micke.rapp@gmail.com>
|
||||
MitaliBo <mitali.bisht14@gmail.com>
|
||||
Nelly Asher <karmelylle@rambler.ru>
|
||||
NocFlame <aad@nocflame.se>
|
||||
Quentin Perez <qperez42@gmail.com>
|
||||
Renovate Bot <bot@renovateapp.com>
|
||||
Shawn Wang <shawn111@gmail.com>
|
||||
Valentin Daviot <valentin.daviot@alterway.fr>
|
||||
valentin.daviot <valentin.daviot@alterway.fr>
|
||||
welderpb <welderpb@users.noreply.github.com>
|
||||
Дмитрий Шульгачик <tech@uniplug.ru>
|
||||
@@ -1,5 +1,5 @@
|
||||
# build
|
||||
FROM golang:1.12.6 as builder
|
||||
FROM golang:1.14.4 as builder
|
||||
ENV GO111MODULE=on
|
||||
WORKDIR /go/src/moul.io/sshportal
|
||||
COPY go.mod go.sum ./
|
||||
|
||||
36
Makefile
36
Makefile
@@ -1,18 +1,15 @@
|
||||
GIT_SHA ?= $(shell git rev-parse HEAD)
|
||||
GIT_TAG ?= $(shell git describe --tags --always)
|
||||
GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||
LDFLAGS ?= -X main.GitSha=$(GIT_SHA) -X main.GitTag=$(GIT_TAG) -X main.GitBranch=$(GIT_BRANCH)
|
||||
VERSION ?= $(shell grep 'VERSION =' main.go | cut -d'"' -f2)
|
||||
GOPKG ?= moul.io/sshportal
|
||||
GOBINS ?= .
|
||||
DOCKER_IMAGE ?= moul/sshportal
|
||||
|
||||
VERSION ?= `git describe --tags --always`
|
||||
VCS_REF ?= `git rev-parse --short HEAD`
|
||||
GO_INSTALL_OPTS = -ldflags="-X main.GitSha=$(VCS_REF) -X main.GitTag=$(VERSION)"
|
||||
|
||||
include rules.mk
|
||||
|
||||
DB_VERSION ?= v$(shell grep -E 'ID: "[0-9]+",' pkg/bastion/dbinit.go | tail -n 1 | cut -d'"' -f2)
|
||||
AES_KEY ?= my-dummy-aes-key
|
||||
GO ?= GO111MODULE=on go
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
$(GO) install -v -ldflags '$(LDFLAGS)' .
|
||||
|
||||
.PHONY: docker.build
|
||||
docker.build:
|
||||
docker build -t moul/sshportal .
|
||||
|
||||
.PHONY: integration
|
||||
integration:
|
||||
@@ -27,19 +24,10 @@ dev:
|
||||
-$(GO) get github.com/githubnemo/CompileDaemon
|
||||
CompileDaemon -exclude-dir=.git -exclude=".#*" -color=true -command="./sshportal server --debug --bind-address=:$(PORT) --aes-key=$(AES_KEY) $(EXTRA_RUN_OPTS)" .
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(GO) test -i ./...
|
||||
$(GO) test -v ./...
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
golangci-lint run --verbose ./...
|
||||
|
||||
.PHONY: backup
|
||||
backup:
|
||||
mkdir -p data/backups
|
||||
cp sshportal.db data/backups/$(shell date +%s)-$(VERSION)-sshportal.sqlite
|
||||
cp sshportal.db data/backups/$(shell date +%s)-$(DB_VERSION)-sshportal.sqlite
|
||||
|
||||
doc:
|
||||
dot -Tsvg ./.assets/overview.dot > ./.assets/overview.svg
|
||||
|
||||
10
README.md
10
README.md
@@ -58,6 +58,8 @@ Shared connection to localhost closed.
|
||||
$
|
||||
```
|
||||
|
||||
If the association fails and you are promted for a password, verify that the host you're connecting from has a SSH key set up or generate one with ```ssh-keygen -t rsa```
|
||||
|
||||
Drop an interactive administrator shell
|
||||
|
||||
```console
|
||||
@@ -158,7 +160,7 @@ If you need to invite multiple people to an event (hackathon, course, etc), the
|
||||
* Sensitive data encryption
|
||||
* Session management (see active connections, history, stats, stop)
|
||||
* Audit log (logging every user action)
|
||||
* Record TTY Session
|
||||
* Record TTY Session (with [ttyrec](https://en.wikipedia.org/wiki/Ttyrec) format, use `ttyplay` for replay)
|
||||
* Tunnels logging
|
||||
* Host Keys verifications shared across users
|
||||
* Healthcheck user (replying OK to any user)
|
||||
@@ -178,6 +180,8 @@ If you need to invite multiple people to an event (hackathon, course, etc), the
|
||||
**(Known) limitations**
|
||||
|
||||
* Does not work (yet?) with [`mosh`](https://mosh.org/)
|
||||
* It is not possible for a user to access a host with the same name as the user. This is easily circumvented by changing the user name, especially since the most common use cases does not expose it.
|
||||
* It is not possible access a host named `healthcheck` as this is a built in command.
|
||||
|
||||
---
|
||||
|
||||
@@ -232,7 +236,7 @@ docker logs -f sshportal
|
||||
Get the latest version using GO.
|
||||
|
||||
```sh
|
||||
go get -u moul.io/sshportal
|
||||
GO111MODULE=on go get -u moul.io/sshportal
|
||||
```
|
||||
|
||||
---
|
||||
@@ -267,7 +271,7 @@ cp sshportal.db sshportal.db.bkp
|
||||
|
||||
`sshportal` embeds a configuration CLI.
|
||||
|
||||
By default, the configuration user is `admin`, (can be changed using `--config-user=<value>` when starting the server.
|
||||
By default, the configuration user is `admin`, (can be changed using `--config-user=<value>` when starting the server. The shell is also accessible through `ssh [username]@portal.example.org`.
|
||||
|
||||
Each commands can be run directly by using this syntax: `ssh admin@portal.example.org <command> [args]`:
|
||||
|
||||
|
||||
28
go.mod
28
go.mod
@@ -1,35 +1,33 @@
|
||||
module moul.io/sshportal
|
||||
|
||||
require (
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239
|
||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/creack/pty v1.1.9 // indirect
|
||||
github.com/creack/pty v1.1.11 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/docker v1.13.1
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||
github.com/gliderlabs/ssh v0.2.2
|
||||
github.com/gliderlabs/ssh v0.3.0
|
||||
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
|
||||
github.com/jinzhu/gorm v1.9.12
|
||||
github.com/jinzhu/gorm v1.9.14
|
||||
github.com/kr/pty v1.1.8
|
||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.8 // indirect
|
||||
github.com/mattn/go-colorable v0.1.6 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
|
||||
github.com/moby/moby v0.7.3-0.20190103212154-2b7e084dc98b
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/reiver/go-oi v1.0.0
|
||||
github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e
|
||||
github.com/sabban/bastion v0.0.0-20180110125408-b9d3c9b1f4d3
|
||||
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4-0.20190330032615-68dc04aab96a
|
||||
github.com/urfave/cli v1.22.2
|
||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4
|
||||
github.com/urfave/cli v1.22.4
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect
|
||||
gopkg.in/gormigrate.v1 v1.6.0
|
||||
moul.io/srand v1.4.0
|
||||
)
|
||||
|
||||
go 1.12.6
|
||||
go 1.14
|
||||
|
||||
60
go.sum
60
go.sum
@@ -1,31 +1,33 @@
|
||||
cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
|
||||
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/gliderlabs/ssh v0.3.0 h1:7GcKy4erEljCE/QeQ2jTVpu+3f3zkpZOxOJjFYkMqYU=
|
||||
github.com/gliderlabs/ssh v0.3.0/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
@@ -43,6 +45,8 @@ github.com/jinzhu/gorm v1.9.2 h1:lCvgEaqe/HVE+tjAR2mt4HbbHAZsQOv3XAZiEZV37iw=
|
||||
github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
|
||||
github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
|
||||
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
|
||||
github.com/jinzhu/gorm v1.9.14 h1:Kg3ShyTPcM6nzVo148fRrcMO6MNKuqtOUwnzqMgVniM=
|
||||
github.com/jinzhu/gorm v1.9.14/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYXJi4pg1ZKM7nxc5AfXfojeLLW7O5J3k=
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
@@ -61,23 +65,21 @@ github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
|
||||
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/moby/moby v0.7.3-0.20190103212154-2b7e084dc98b h1:z/nBoaNNRdlg5oyabuQyZshr/YsANYEcjI+IiNT/U6U=
|
||||
github.com/moby/moby v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
|
||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
@@ -95,28 +97,34 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 h1:hBSHahWMEgzwRyS6dRpxY0XyjZsHyQ61s084wo5PJe0=
|
||||
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4-0.20190330032615-68dc04aab96a h1:XmieTxr5Ejfoo1izsMZO4qWqOTpYagCqNMJyP87ONS0=
|
||||
github.com/smartystreets/goconvey v1.6.4-0.20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
|
||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6 h1:Sy5bstxEqwwbYs6n0/pBuxKENqOeZUgD45Gp3Q3pqLg=
|
||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867 h1:JoRuNIf+rpHl+VhScRQQvzbHed86tKkqwPMV34T8myw=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
||||
10
main.go
10
main.go
@@ -13,14 +13,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// Version should be updated by hand at each release
|
||||
Version = "1.10.0+dev"
|
||||
// GitTag will be overwritten automatically by the build system
|
||||
GitTag string
|
||||
GitTag = "n/a"
|
||||
// GitSha will be overwritten automatically by the build system
|
||||
GitSha string
|
||||
// GitBranch will be overwritten automatically by the build system
|
||||
GitBranch string
|
||||
GitSha = "n/a"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -29,7 +25,7 @@ func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = path.Base(os.Args[0])
|
||||
app.Author = "Manfred Touron"
|
||||
app.Version = Version + " (" + GitSha + ")"
|
||||
app.Version = GitTag + " (" + GitSha + ")"
|
||||
app.Email = "https://moul.io/sshportal"
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ func (a byWeight) Len() int { return len(a) }
|
||||
func (a byWeight) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a byWeight) Less(i, j int) bool { return a[i].Weight < a[j].Weight }
|
||||
|
||||
func checkACLs(user dbmodels.User, host dbmodels.Host) (string, error) {
|
||||
func checkACLs(user dbmodels.User, host dbmodels.Host) string {
|
||||
// shared ACLs between user and host
|
||||
aclMap := map[uint]*dbmodels.ACL{}
|
||||
for _, userGroup := range user.Groups {
|
||||
@@ -30,7 +30,7 @@ func checkACLs(user dbmodels.User, host dbmodels.Host) (string, error) {
|
||||
|
||||
// deny by default if no shared ACL
|
||||
if len(aclMap) == 0 {
|
||||
return string(dbmodels.ACLActionDeny), nil // default action
|
||||
return string(dbmodels.ACLActionDeny) // default action
|
||||
}
|
||||
|
||||
// transform map to slice and sort it
|
||||
@@ -40,5 +40,5 @@ func checkACLs(user dbmodels.User, host dbmodels.Host) (string, error) {
|
||||
}
|
||||
sort.Sort(byWeight(acls))
|
||||
|
||||
return acls[0].Action, nil
|
||||
return acls[0].Action
|
||||
}
|
||||
|
||||
@@ -43,8 +43,7 @@ func TestCheckACLs(t *testing.T) {
|
||||
db.Preload("Groups").Preload("Groups.ACLs").Find(&users)
|
||||
|
||||
// test
|
||||
action, err := checkACLs(users[0], hosts[0])
|
||||
c.So(err, ShouldBeNil)
|
||||
action := checkACLs(users[0], hosts[0])
|
||||
c.So(action, ShouldEqual, dbmodels.ACLActionAllow)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -261,14 +261,14 @@ func DBInit(db *gorm.DB) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var users []dbmodels.User
|
||||
var users []*dbmodels.User
|
||||
if err := db.Preload("Roles").Where("is_admin = ?", true).Find(&users).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
user.Roles = append(user.Roles, &adminRole)
|
||||
if err := tx.Save(&user).Error; err != nil {
|
||||
if err := tx.Save(user).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -358,7 +358,7 @@ func DBInit(db *gorm.DB) error {
|
||||
}, {
|
||||
ID: "24",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
var userKeys []dbmodels.UserKey
|
||||
var userKeys []*dbmodels.UserKey
|
||||
if err := db.Find(&userKeys).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -369,7 +369,7 @@ func DBInit(db *gorm.DB) error {
|
||||
return err
|
||||
}
|
||||
userKey.AuthorizedKey = string(gossh.MarshalAuthorizedKey(key))
|
||||
if err := db.Model(&userKey).Updates(&userKey).Error; err != nil {
|
||||
if err := db.Model(userKey).Updates(userKey).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -422,14 +422,14 @@ func DBInit(db *gorm.DB) error {
|
||||
}, {
|
||||
ID: "27",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
var sessions []dbmodels.Session
|
||||
var sessions []*dbmodels.Session
|
||||
if err := db.Find(&sessions).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, session := range sessions {
|
||||
if session.StoppedAt != nil && session.StoppedAt.IsZero() {
|
||||
if err := db.Model(&session).Updates(map[string]interface{}{"stopped_at": nil}).Error; err != nil {
|
||||
if err := db.Model(session).Updates(map[string]interface{}{"stopped_at": nil}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package bastion // import "moul.io/sshportal/pkg/bastion"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -20,7 +19,7 @@ type sessionConfig struct {
|
||||
ClientConfig *gossh.ClientConfig
|
||||
}
|
||||
|
||||
func multiChannelHandler(srv *ssh.Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx ssh.Context, configs []sessionConfig, sessionID uint) error {
|
||||
func multiChannelHandler(conn *gossh.ServerConn, newChan gossh.NewChannel, ctx ssh.Context, configs []sessionConfig, sessionID uint) error {
|
||||
var lastClient *gossh.Client
|
||||
switch newChan.ChannelType() {
|
||||
case "session":
|
||||
@@ -124,6 +123,7 @@ func pipe(lreqs, rreqs <-chan *gossh.Request, lch, rch gossh.Channel, logsLocati
|
||||
}()
|
||||
|
||||
errch := make(chan error, 1)
|
||||
quit := make(chan string, 1)
|
||||
channeltype := newChan.ChannelType()
|
||||
|
||||
filename := strings.Join([]string{logsLocation, "/", user, "-", username, "-", channeltype, "-", fmt.Sprint(sessionID), "-", time.Now().Format(time.RFC3339)}, "") // get user
|
||||
@@ -139,15 +139,15 @@ func pipe(lreqs, rreqs <-chan *gossh.Request, lch, rch gossh.Channel, logsLocati
|
||||
log.Printf("Session %v is recorded in %v", channeltype, filename)
|
||||
if channeltype == "session" {
|
||||
wrappedlch := logchannel.New(lch, f)
|
||||
go func() {
|
||||
go func(quit chan string) {
|
||||
_, _ = io.Copy(wrappedlch, rch)
|
||||
errch <- errors.New("lch closed the connection")
|
||||
}()
|
||||
quit <- "rch"
|
||||
}(quit)
|
||||
|
||||
go func() {
|
||||
go func(quit chan string) {
|
||||
_, _ = io.Copy(rch, lch)
|
||||
errch <- errors.New("rch closed the connection")
|
||||
}()
|
||||
quit <- "lch"
|
||||
}(quit)
|
||||
}
|
||||
if channeltype == "direct-tcpip" {
|
||||
d := logTunnelForwardData{}
|
||||
@@ -156,23 +156,19 @@ func pipe(lreqs, rreqs <-chan *gossh.Request, lch, rch gossh.Channel, logsLocati
|
||||
}
|
||||
wrappedlch := newLogTunnel(lch, f, d.SourceHost)
|
||||
wrappedrch := newLogTunnel(rch, f, d.DestinationHost)
|
||||
go func() {
|
||||
go func(quit chan string) {
|
||||
_, _ = io.Copy(wrappedlch, rch)
|
||||
errch <- errors.New("lch closed the connection")
|
||||
}()
|
||||
quit <- "rch"
|
||||
}(quit)
|
||||
|
||||
go func() {
|
||||
go func(quit chan string) {
|
||||
_, _ = io.Copy(wrappedrch, lch)
|
||||
errch <- errors.New("rch closed the connection")
|
||||
}()
|
||||
quit <- "lch"
|
||||
}(quit)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case req := <-lreqs: // forward ssh requests from local to remote
|
||||
if req == nil {
|
||||
return nil
|
||||
}
|
||||
go func(quit chan string) {
|
||||
for req := range lreqs {
|
||||
b, err := rch.SendRequest(req.Type, req.WantReply, req.Payload)
|
||||
if req.Type == "exec" {
|
||||
wrappedlch := logchannel.New(lch, f)
|
||||
@@ -183,24 +179,58 @@ func pipe(lreqs, rreqs <-chan *gossh.Request, lch, rch gossh.Channel, logsLocati
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
errch <- err
|
||||
}
|
||||
if err2 := req.Reply(b, nil); err2 != nil {
|
||||
return err2
|
||||
}
|
||||
case req := <-rreqs: // forward ssh requests from remote to local
|
||||
if req == nil {
|
||||
return nil
|
||||
errch <- err2
|
||||
}
|
||||
}
|
||||
quit <- "lreqs"
|
||||
}(quit)
|
||||
|
||||
go func(quit chan string) {
|
||||
for req := range rreqs {
|
||||
b, err := lch.SendRequest(req.Type, req.WantReply, req.Payload)
|
||||
if err != nil {
|
||||
return err
|
||||
errch <- err
|
||||
}
|
||||
if err2 := req.Reply(b, nil); err2 != nil {
|
||||
return err2
|
||||
errch <- err2
|
||||
}
|
||||
}
|
||||
quit <- "rreqs"
|
||||
}(quit)
|
||||
|
||||
lchEOF, rchEOF, lchClosed, rchClosed := false, false, false, false
|
||||
for {
|
||||
select {
|
||||
case err := <-errch:
|
||||
return err
|
||||
case q := <-quit:
|
||||
switch q {
|
||||
case "lch":
|
||||
lchEOF = true
|
||||
_ = rch.CloseWrite()
|
||||
case "rch":
|
||||
rchEOF = true
|
||||
_ = lch.CloseWrite()
|
||||
case "lreqs":
|
||||
lchClosed = true
|
||||
case "rreqs":
|
||||
rchClosed = true
|
||||
}
|
||||
|
||||
if lchEOF && lchClosed && !rchClosed {
|
||||
rch.Close()
|
||||
}
|
||||
|
||||
if rchEOF && rchClosed && !lchClosed {
|
||||
lch.Close()
|
||||
}
|
||||
|
||||
if lchEOF && rchEOF && lchClosed && rchClosed {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ import (
|
||||
|
||||
shlex "github.com/anmitsu/go-shlex"
|
||||
"github.com/asaskevich/govalidator"
|
||||
"github.com/docker/docker/pkg/namesgenerator"
|
||||
humanize "github.com/dustin/go-humanize"
|
||||
"github.com/gliderlabs/ssh"
|
||||
"github.com/mgutz/ansi"
|
||||
"github.com/moby/moby/pkg/namesgenerator"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/urfave/cli"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
@@ -41,7 +41,7 @@ const (
|
||||
naMessage = "n/a"
|
||||
)
|
||||
|
||||
func shell(s ssh.Session, version, gitSha, gitTag, gitBranch string) error {
|
||||
func shell(s ssh.Session, version, gitSha, gitTag string) error {
|
||||
var (
|
||||
sshCommand = s.Command()
|
||||
actx = s.Context().Value(authContextKey).(*authContext)
|
||||
@@ -67,6 +67,8 @@ GLOBAL OPTIONS:
|
||||
app.Writer = s
|
||||
app.HideVersion = true
|
||||
|
||||
dbmodels.InitValidator()
|
||||
|
||||
var (
|
||||
myself = &actx.user
|
||||
db = actx.db
|
||||
@@ -173,10 +175,8 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
acls = append(acls, &acl)
|
||||
} else {
|
||||
if err := query.Find(&acls).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := query.Find(&acls).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Bool("quiet") {
|
||||
for _, acl := range acls {
|
||||
@@ -250,14 +250,14 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
|
||||
var acls []dbmodels.ACL
|
||||
var acls []*dbmodels.ACL
|
||||
if err := dbmodels.ACLsByIdentifiers(db, c.Args()).Find(&acls).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tx := db.Begin()
|
||||
for _, acl := range acls {
|
||||
model := tx.Model(&acl)
|
||||
model := tx.Model(acl)
|
||||
update := dbmodels.ACL{
|
||||
Action: c.String("action"),
|
||||
HostPattern: c.String("pattern"),
|
||||
@@ -477,6 +477,7 @@ GLOBAL OPTIONS:
|
||||
}
|
||||
}
|
||||
for _, host := range config.Hosts {
|
||||
host := host
|
||||
crypto.HostDecrypt(actx.aesKey, host)
|
||||
if !c.Bool("decrypt") {
|
||||
if err := crypto.HostEncrypt(actx.aesKey, host); err != nil {
|
||||
@@ -489,30 +490,35 @@ GLOBAL OPTIONS:
|
||||
}
|
||||
}
|
||||
for _, user := range config.Users {
|
||||
user := user
|
||||
if err := tx.FirstOrCreate(&user).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, acl := range config.ACLs {
|
||||
acl := acl
|
||||
if err := tx.FirstOrCreate(&acl).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, hostGroup := range config.HostGroups {
|
||||
hostGroup := hostGroup
|
||||
if err := tx.FirstOrCreate(&hostGroup).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, userGroup := range config.UserGroups {
|
||||
userGroup := userGroup
|
||||
if err := tx.FirstOrCreate(&userGroup).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, sshKey := range config.SSHKeys {
|
||||
sshKey := sshKey
|
||||
crypto.SSHKeyDecrypt(actx.aesKey, sshKey)
|
||||
if !c.Bool("decrypt") {
|
||||
if err := crypto.SSHKeyEncrypt(actx.aesKey, sshKey); err != nil {
|
||||
@@ -525,24 +531,28 @@ GLOBAL OPTIONS:
|
||||
}
|
||||
}
|
||||
for _, userKey := range config.UserKeys {
|
||||
userKey := userKey
|
||||
if err := tx.FirstOrCreate(&userKey).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, setting := range config.Settings {
|
||||
setting := setting
|
||||
if err := tx.FirstOrCreate(&setting).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, session := range config.Sessions {
|
||||
session := session
|
||||
if err := tx.FirstOrCreate(&session).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, event := range config.Events {
|
||||
event := event
|
||||
if err := tx.FirstOrCreate(&event).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
@@ -612,10 +622,8 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
events = append(events, event)
|
||||
} else {
|
||||
if err := query.Find(&events).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := query.Find(&events).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Bool("quiet") {
|
||||
@@ -799,10 +807,8 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
hosts = append(hosts, &host)
|
||||
} else {
|
||||
if err := query.Find(&hosts).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := query.Find(&hosts).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Bool("quiet") {
|
||||
@@ -820,7 +826,7 @@ GLOBAL OPTIONS:
|
||||
authKey := ""
|
||||
if host.SSHKeyID > 0 {
|
||||
var key dbmodels.SSHKey
|
||||
db.Model(&host).Related(&key)
|
||||
db.Model(host).Related(&key)
|
||||
authKey = key.Name
|
||||
}
|
||||
groupNames := []string{}
|
||||
@@ -830,7 +836,7 @@ GLOBAL OPTIONS:
|
||||
var hop string
|
||||
if host.HopID != 0 {
|
||||
var hopHost dbmodels.Host
|
||||
db.Model(&host).Related(&hopHost, "HopID")
|
||||
db.Model(host).Related(&hopHost, "HopID")
|
||||
hop = hopHost.Name
|
||||
} else {
|
||||
hop = ""
|
||||
@@ -900,6 +906,7 @@ GLOBAL OPTIONS:
|
||||
|
||||
tx := db.Begin()
|
||||
for _, host := range hosts {
|
||||
host := host
|
||||
model := tx.Model(&host)
|
||||
// simple fields
|
||||
for _, fieldname := range []string{"name", "comment"} {
|
||||
@@ -1063,10 +1070,8 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
hostGroups = append(hostGroups, &hostGroup)
|
||||
} else {
|
||||
if err := query.Find(&hostGroups).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := query.Find(&hostGroups).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Bool("quiet") {
|
||||
@@ -1127,7 +1132,7 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
|
||||
var hostgroups []dbmodels.HostGroup
|
||||
var hostgroups []*dbmodels.HostGroup
|
||||
if err := dbmodels.HostGroupsByIdentifiers(db, c.Args()).Find(&hostgroups).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1138,7 +1143,7 @@ GLOBAL OPTIONS:
|
||||
|
||||
tx := db.Begin()
|
||||
for _, hostgroup := range hostgroups {
|
||||
model := tx.Model(&hostgroup)
|
||||
model := tx.Model(hostgroup)
|
||||
// simple fields
|
||||
for _, fieldname := range []string{"name", "comment"} {
|
||||
if c.String(fieldname) != "" {
|
||||
@@ -1180,9 +1185,9 @@ GLOBAL OPTIONS:
|
||||
fmt.Fprintf(s, "User email: %s\n", myself.Email)
|
||||
fmt.Fprintf(s, "Version: %s\n", version)
|
||||
fmt.Fprintf(s, "GIT SHA: %s\n", gitSha)
|
||||
fmt.Fprintf(s, "GIT Branch: %s\n", gitBranch)
|
||||
fmt.Fprintf(s, "GIT Tag: %s\n", gitTag)
|
||||
|
||||
// FIXME: gormigrate version
|
||||
// FIXME: add info about current server (network, cpu, ram, OS)
|
||||
// FIXME: add info about current user
|
||||
// FIXME: add active connections
|
||||
@@ -1342,10 +1347,8 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
sshKeys = append(sshKeys, &sshKey)
|
||||
} else {
|
||||
if err := query.Find(&sshKeys).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := query.Find(&sshKeys).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Bool("quiet") {
|
||||
for _, sshKey := range sshKeys {
|
||||
@@ -1584,10 +1587,8 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
users = append(users, &user)
|
||||
} else {
|
||||
if err := query.Find(&users).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := query.Find(&users).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Bool("quiet") {
|
||||
for _, user := range users {
|
||||
@@ -1661,7 +1662,7 @@ GLOBAL OPTIONS:
|
||||
}
|
||||
|
||||
// FIXME: check if unset-admin + user == myself
|
||||
var users []dbmodels.User
|
||||
var users []*dbmodels.User
|
||||
if err := dbmodels.UsersByIdentifiers(db, c.Args()).Find(&users).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1676,7 +1677,7 @@ GLOBAL OPTIONS:
|
||||
|
||||
tx := db.Begin()
|
||||
for _, user := range users {
|
||||
model := tx.Model(&user)
|
||||
model := tx.Model(user)
|
||||
// simple fields
|
||||
for _, fieldname := range []string{"name", "email", "comment"} {
|
||||
if c.String(fieldname) != "" {
|
||||
@@ -1814,10 +1815,8 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
userGroups = append(userGroups, &userGroup)
|
||||
} else {
|
||||
if err := query.Find(&userGroups).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := query.Find(&userGroups).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Bool("quiet") {
|
||||
for _, userGroup := range userGroups {
|
||||
@@ -1877,7 +1876,7 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
|
||||
var usergroups []dbmodels.UserGroup
|
||||
var usergroups []*dbmodels.UserGroup
|
||||
if err := dbmodels.UserGroupsByIdentifiers(db, c.Args()).Find(&usergroups).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1888,7 +1887,7 @@ GLOBAL OPTIONS:
|
||||
|
||||
tx := db.Begin()
|
||||
for _, usergroup := range usergroups {
|
||||
model := tx.Model(&usergroup)
|
||||
model := tx.Model(usergroup)
|
||||
// simple fields
|
||||
for _, fieldname := range []string{"name", "comment"} {
|
||||
if c.String(fieldname) != "" {
|
||||
@@ -2001,10 +2000,8 @@ GLOBAL OPTIONS:
|
||||
return err
|
||||
}
|
||||
userKeys = append(userKeys, &userKey)
|
||||
} else {
|
||||
if err := query.Find(&userKeys).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := query.Find(&userKeys).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Bool("quiet") {
|
||||
for _, userKey := range userKeys {
|
||||
@@ -2112,7 +2109,6 @@ GLOBAL OPTIONS:
|
||||
|
||||
factor := 1
|
||||
for len(sessions) >= limit*factor {
|
||||
|
||||
var additionnalSessions []*dbmodels.Session
|
||||
|
||||
offset = limit * factor
|
||||
|
||||
@@ -149,7 +149,7 @@ func ChannelHandler(srv *ssh.Server, conn *gossh.ServerConn, newChan gossh.NewCh
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
err = multiChannelHandler(srv, conn, newChan, ctx, sessionConfigs, sess.ID)
|
||||
err = multiChannelHandler(conn, newChan, ctx, sessionConfigs, sess.ID)
|
||||
if err != nil {
|
||||
log.Printf("Error: %v", err)
|
||||
}
|
||||
@@ -160,8 +160,7 @@ func ChannelHandler(srv *ssh.Server, conn *gossh.ServerConn, newChan gossh.NewCh
|
||||
ErrMsg: fmt.Sprintf("%v", err),
|
||||
StoppedAt: &now,
|
||||
}
|
||||
switch sessUpdate.ErrMsg {
|
||||
case "lch closed the connection", "rch closed the connection":
|
||||
if err == nil {
|
||||
sessUpdate.ErrMsg = ""
|
||||
}
|
||||
actx.db.Model(&sess).Updates(&sessUpdate)
|
||||
@@ -205,13 +204,11 @@ func bastionClientConfig(ctx ssh.Context, host *dbmodels.Host) (*gossh.ClientCon
|
||||
if err = actx.db.Preload("Groups").Preload("Groups.ACLs").Where("id = ?", host.ID).First(&tmpHost).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
action, err2 := checkACLs(tmpUser, tmpHost)
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
|
||||
action := checkACLs(tmpUser, tmpHost)
|
||||
switch action {
|
||||
case string(dbmodels.ACLActionAllow):
|
||||
// do nothing
|
||||
case string(dbmodels.ACLActionDeny):
|
||||
return nil, fmt.Errorf("you don't have permission to that host")
|
||||
default:
|
||||
@@ -220,7 +217,7 @@ func bastionClientConfig(ctx ssh.Context, host *dbmodels.Host) (*gossh.ClientCon
|
||||
return clientConfig, nil
|
||||
}
|
||||
|
||||
func ShellHandler(s ssh.Session, version, gitSha, gitTag, gitBranch string) {
|
||||
func ShellHandler(s ssh.Session, version, gitSha, gitTag string) {
|
||||
actx := s.Context().Value(authContextKey).(*authContext)
|
||||
if actx.userType() != userTypeHealthcheck {
|
||||
log.Printf("New connection(shell): sshUser=%q remote=%q local=%q command=%q dbUser=id:%d,email:%s", s.User(), s.RemoteAddr(), s.LocalAddr(), s.Command(), actx.user.ID, actx.user.Email)
|
||||
@@ -241,7 +238,7 @@ func ShellHandler(s ssh.Session, version, gitSha, gitTag, gitBranch string) {
|
||||
fmt.Fprintln(s, "OK")
|
||||
return
|
||||
case userTypeShell:
|
||||
if err := shell(s, version, gitSha, gitTag, gitBranch); err != nil {
|
||||
if err := shell(s, version, gitSha, gitTag); err != nil {
|
||||
fmt.Fprintf(s, "error: %v\n", err)
|
||||
_ = s.Exit(1)
|
||||
}
|
||||
|
||||
@@ -5,12 +5,10 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"github.com/jinzhu/gorm"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
@@ -166,18 +164,6 @@ const (
|
||||
BastionSchemeTelnet BastionScheme = "telnet"
|
||||
)
|
||||
|
||||
func init() {
|
||||
unixUserRegexp := regexp.MustCompile("[a-z_][a-z0-9_-]*")
|
||||
|
||||
govalidator.CustomTypeTagMap.Set("unix_user", govalidator.CustomTypeValidator(func(i interface{}, context interface{}) bool {
|
||||
name, ok := i.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return unixUserRegexp.MatchString(name)
|
||||
}))
|
||||
}
|
||||
|
||||
// Host helpers
|
||||
|
||||
func (host *Host) DialAddr() string {
|
||||
|
||||
19
pkg/dbmodels/validator.go
Normal file
19
pkg/dbmodels/validator.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package dbmodels
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
)
|
||||
|
||||
func InitValidator() {
|
||||
unixUserRegexp := regexp.MustCompile("[a-z_][a-z0-9_-]*")
|
||||
|
||||
govalidator.CustomTypeTagMap.Set("unix_user", govalidator.CustomTypeValidator(func(i interface{}, context interface{}) bool {
|
||||
name, ok := i.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return unixUserRegexp.MatchString(name)
|
||||
}))
|
||||
}
|
||||
278
rules.mk
Normal file
278
rules.mk
Normal file
@@ -0,0 +1,278 @@
|
||||
# +--------------------------------------------------------------+
|
||||
# | * * * moul.io/rules.mk |
|
||||
# +--------------------------------------------------------------+
|
||||
# | |
|
||||
# | ++ ______________________________________ |
|
||||
# | ++++ / \ |
|
||||
# | ++++ | | |
|
||||
# | ++++++++++ | https://moul.io/rules.mk is a set | |
|
||||
# | +++ | | of common Makefile rules that can | |
|
||||
# | ++ | | be configured from the Makefile | |
|
||||
# | + -== ==| | or with environment variables. | |
|
||||
# | ( <*> <*> | | |
|
||||
# | | | /| Manfred Touron | |
|
||||
# | | _) / | manfred.life | |
|
||||
# | | +++ / \______________________________________/ |
|
||||
# | \ =+ / |
|
||||
# | \ + |
|
||||
# | |\++++++ |
|
||||
# | | ++++ ||// |
|
||||
# | ___| |___ _||/__ __|
|
||||
# | / --- \ \| ||| __ _ ___ __ __/ /|
|
||||
# |/ | | \ \ / / ' \/ _ \/ // / / |
|
||||
# || | | | | | /_/_/_/\___/\_,_/_/ |
|
||||
# +--------------------------------------------------------------+
|
||||
|
||||
all: help
|
||||
|
||||
##
|
||||
## Common helpers
|
||||
##
|
||||
|
||||
rwildcard = $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
|
||||
|
||||
##
|
||||
## rules.mk
|
||||
##
|
||||
ifneq ($(wildcard rules.mk),)
|
||||
.PHONY: rulesmk.bumpdeps
|
||||
rulesmk.bumpdeps:
|
||||
wget -O rules.mk https://raw.githubusercontent.com/moul/rules.mk/master/rules.mk
|
||||
BUMPDEPS_STEPS += rulesmk.bumpdeps
|
||||
endif
|
||||
|
||||
##
|
||||
## Maintainer
|
||||
##
|
||||
|
||||
ifneq ($(wildcard .git/HEAD),)
|
||||
.PHONY: generate.authors
|
||||
generate.authors: AUTHORS
|
||||
AUTHORS: .git/
|
||||
echo "# This file lists all individuals having contributed content to the repository." > AUTHORS
|
||||
echo "# For how it is generated, see 'https://github.com/moul/rules.mk'" >> AUTHORS
|
||||
echo >> AUTHORS
|
||||
git log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf >> AUTHORS
|
||||
GENERATE_STEPS += generate.authors
|
||||
endif
|
||||
|
||||
##
|
||||
## Golang
|
||||
##
|
||||
|
||||
ifndef GOPKG
|
||||
ifneq ($(wildcard go.mod),)
|
||||
GOPKG = $(shell sed '/module/!d;s/^omdule\ //' go.mod)
|
||||
endif
|
||||
endif
|
||||
ifdef GOPKG
|
||||
GO ?= go
|
||||
GOPATH ?= $(HOME)/go
|
||||
GO_INSTALL_OPTS ?=
|
||||
GO_TEST_OPTS ?= -test.timeout=30s
|
||||
GOMOD_DIR ?= .
|
||||
GOCOVERAGE_FILE ?= ./coverage.txt
|
||||
|
||||
ifdef GOBINS
|
||||
.PHONY: go.install
|
||||
go.install:
|
||||
@set -e; for dir in $(GOBINS); do ( set -xe; \
|
||||
cd $$dir; \
|
||||
$(GO) install $(GO_INSTALL_OPTS) .; \
|
||||
); done
|
||||
INSTALL_STEPS += go.install
|
||||
|
||||
.PHONY: go.release
|
||||
go.release:
|
||||
goreleaser --snapshot --skip-publish --rm-dist
|
||||
@echo -n "Do you want to release? [y/N] " && read ans && \
|
||||
if [ $${ans:-N} = y ]; then set -xe; goreleaser --rm-dist; fi
|
||||
RELEASE_STEPS += go.release
|
||||
endif
|
||||
|
||||
.PHONY: go.unittest
|
||||
go.unittest:
|
||||
@echo "mode: atomic" > /tmp/gocoverage
|
||||
@set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do (set -e; (set -xe; \
|
||||
cd $$dir; \
|
||||
$(GO) test $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race ./...); \
|
||||
if [ -f /tmp/profile.out ]; then \
|
||||
cat /tmp/profile.out | sed "/mode: atomic/d" >> /tmp/gocoverage; \
|
||||
rm -f /tmp/profile.out; \
|
||||
fi); done
|
||||
@mv /tmp/gocoverage $(GOCOVERAGE_FILE)
|
||||
|
||||
.PHONY: go.checkdoc
|
||||
go.checkdoc:
|
||||
go doc $(GOMOD_DIR)
|
||||
|
||||
.PHONY: go.coverfunc
|
||||
go.coverfunc: go.unittest
|
||||
go tool cover -func=$(GOCOVERAGE_FILE) | grep -v .pb.go: | grep -v .pb.gw.go:
|
||||
|
||||
.PHONY: go.lint
|
||||
go.lint:
|
||||
@set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do ( set -xe; \
|
||||
cd $$dir; \
|
||||
golangci-lint run --verbose ./...; \
|
||||
); done
|
||||
|
||||
.PHONY: go.tidy
|
||||
go.tidy:
|
||||
@set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do ( set -xe; \
|
||||
cd $$dir; \
|
||||
$(GO) mod tidy; \
|
||||
); done
|
||||
|
||||
.PHONY: go.build
|
||||
go.build:
|
||||
@set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do ( set -xe; \
|
||||
cd $$dir; \
|
||||
$(GO) build ./...; \
|
||||
); done
|
||||
|
||||
.PHONY: go.bump-deps
|
||||
go.bumpdeps:
|
||||
@set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do ( set -xe; \
|
||||
cd $$dir; \
|
||||
$(GO) get -u ./...; \
|
||||
); done
|
||||
|
||||
.PHONY: go.bump-deps
|
||||
go.fmt:
|
||||
if ! command -v goimports &>/dev/null; then GO111MODULE=off go get golang.org/x/tools/cmd/goimports; fi
|
||||
@set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do ( set -xe; \
|
||||
cd $$dir; \
|
||||
goimports -w `go list -f '{{.Dir}}' ./...)` \
|
||||
); done
|
||||
|
||||
BUILD_STEPS += go.build
|
||||
BUMPDEPS_STEPS += go.bumpdeps
|
||||
TIDY_STEPS += go.tidy
|
||||
LINT_STEPS += go.lint
|
||||
UNITTEST_STEPS += go.unittest
|
||||
FMT_STEPS += go.fmt
|
||||
endif
|
||||
|
||||
##
|
||||
## Node
|
||||
##
|
||||
|
||||
ifndef NPM_PACKAGES
|
||||
ifneq ($(wildcard package.json),)
|
||||
NPM_PACKAGES = .
|
||||
endif
|
||||
endif
|
||||
ifdef NPM_PACKAGES
|
||||
.PHONY: npm.publish
|
||||
npm.publish:
|
||||
@echo -n "Do you want to npm publish? [y/N] " && read ans && \
|
||||
@if [ $${ans:-N} = y ]; then \
|
||||
set -e; for dir in $(NPM_PACKAGES); do ( set -xe; \
|
||||
cd $$dir; \
|
||||
npm publish --access=public; \
|
||||
); done; \
|
||||
fi
|
||||
RELEASE_STEPS += npm.publish
|
||||
endif
|
||||
|
||||
##
|
||||
## Docker
|
||||
##
|
||||
|
||||
docker_build = docker build \
|
||||
--build-arg VCS_REF=`git rev-parse --short HEAD` \
|
||||
--build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
|
||||
--build-arg VERSION=`git describe --tags --always` \
|
||||
-t "$2" -f "$1" "$(dir $1)"
|
||||
|
||||
ifndef DOCKERFILE_PATH
|
||||
DOCKERFILE_PATH = ./Dockerfile
|
||||
endif
|
||||
ifndef DOCKER_IMAGE
|
||||
ifneq ($(wildcard Dockerfile),)
|
||||
DOCKER_IMAGE = $(notdir $(PWD))
|
||||
endif
|
||||
endif
|
||||
ifdef DOCKER_IMAGE
|
||||
ifneq ($(DOCKER_IMAGE),none)
|
||||
.PHONY: docker.build
|
||||
docker.build:
|
||||
$(call docker_build,$(DOCKERFILE_PATH),$(DOCKER_IMAGE))
|
||||
|
||||
BUILD_STEPS += docker.build
|
||||
endif
|
||||
endif
|
||||
|
||||
##
|
||||
## Common
|
||||
##
|
||||
|
||||
TEST_STEPS += $(UNITTEST_STEPS)
|
||||
TEST_STEPS += $(LINT_STEPS)
|
||||
TEST_STEPS += $(TIDY_STEPS)
|
||||
|
||||
ifneq ($(strip $(TEST_STEPS)),)
|
||||
.PHONY: test
|
||||
test: $(PRE_TEST_STEPS) $(TEST_STEPS)
|
||||
endif
|
||||
|
||||
ifdef INSTALL_STEPS
|
||||
.PHONY: install
|
||||
install: $(PRE_INSTALL_STEPS) $(INSTALL_STEPS)
|
||||
endif
|
||||
|
||||
ifdef UNITTEST_STEPS
|
||||
.PHONY: unittest
|
||||
unittest: $(PRE_UNITTEST_STEPS) $(UNITTEST_STEPS)
|
||||
endif
|
||||
|
||||
ifdef LINT_STEPS
|
||||
.PHONY: lint
|
||||
lint: $(PRE_LINT_STEPS) $(FMT_STEPS) $(LINT_STEPS)
|
||||
endif
|
||||
|
||||
ifdef TIDY_STEPS
|
||||
.PHONY: tidy
|
||||
tidy: $(PRE_TIDY_STEPS) $(TIDY_STEPS)
|
||||
endif
|
||||
|
||||
ifdef BUILD_STEPS
|
||||
.PHONY: build
|
||||
build: $(PRE_BUILD_STEPS) $(BUILD_STEPS)
|
||||
endif
|
||||
|
||||
ifdef RELEASE_STEPS
|
||||
.PHONY: release
|
||||
release: $(PRE_RELEASE_STEPS) $(RELEASE_STEPS)
|
||||
endif
|
||||
|
||||
ifdef BUMPDEPS_STEPS
|
||||
.PHONY: bumpdeps
|
||||
bumpdeps: $(PRE_BUMDEPS_STEPS) $(BUMPDEPS_STEPS)
|
||||
endif
|
||||
|
||||
ifdef FMT_STEPS
|
||||
.PHONY: fmt
|
||||
fmt: $(PRE_FMT_STEPS) $(FMT_STEPS)
|
||||
endif
|
||||
|
||||
ifdef GENERATE_STEPS
|
||||
.PHONY: generate
|
||||
generate: $(PRE_GENERATE_STEPS) $(GENERATE_STEPS)
|
||||
endif
|
||||
|
||||
.PHONY: help
|
||||
help::
|
||||
@echo "General commands:"
|
||||
@[ "$(BUILD_STEPS)" != "" ] && echo " build" || true
|
||||
@[ "$(BUMPDEPS_STEPS)" != "" ] && echo " bumpdeps" || true
|
||||
@[ "$(FMT_STEPS)" != "" ] && echo " fmt" || true
|
||||
@[ "$(GENERATE_STEPS)" != "" ] && echo " generate" || true
|
||||
@[ "$(INSTALL_STEPS)" != "" ] && echo " install" || true
|
||||
@[ "$(LINT_STEPS)" != "" ] && echo " lint" || true
|
||||
@[ "$(RELEASE_STEPS)" != "" ] && echo " release" || true
|
||||
@[ "$(TEST_STEPS)" != "" ] && echo " test" || true
|
||||
@[ "$(TIDY_STEPS)" != "" ] && echo " tidy" || true
|
||||
@[ "$(UNITTEST_STEPS)" != "" ] && echo " unittest" || true
|
||||
@# FIXME: list other commands
|
||||
@@ -89,8 +89,8 @@ func server(c *serverConfig) (err error) {
|
||||
// configure server
|
||||
srv := &ssh.Server{
|
||||
Addr: c.bindAddr,
|
||||
Handler: func(s ssh.Session) { bastion.ShellHandler(s, Version, GitSha, GitTag, GitBranch) }, // ssh.Server.Handler is the handler for the DefaultSessionHandler
|
||||
Version: fmt.Sprintf("sshportal-%s", Version),
|
||||
Handler: func(s ssh.Session) { bastion.ShellHandler(s, GitTag, GitSha, GitTag) }, // ssh.Server.Handler is the handler for the DefaultSessionHandler
|
||||
Version: fmt.Sprintf("sshportal-%s", GitTag),
|
||||
ChannelHandlers: map[string]ssh.ChannelHandler{
|
||||
"default": bastion.ChannelHandler,
|
||||
},
|
||||
|
||||
14
testserver_unsupported.go
Normal file
14
testserver_unsupported.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// +build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// testServer is an hidden handler used for integration tests
|
||||
func testServer(c *cli.Context) error {
|
||||
return fmt.Errorf("not available on windows")
|
||||
}
|
||||
Reference in New Issue
Block a user