mirror of
https://github.com/moul/sshportal.git
synced 2024-09-20 15:06:07 +08:00
commit
669577de47
|
@ -1,7 +1,7 @@
|
|||
defaults: &defaults
|
||||
working_directory: /go/src/moul.io/sshportal
|
||||
docker:
|
||||
- image: circleci/golang:1.15.2
|
||||
- image: circleci/golang:1.16.2
|
||||
environment:
|
||||
GO111MODULE: "on"
|
||||
|
||||
|
|
30
.github/ISSUE_TEMPLATE.md
vendored
30
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,25 +1,15 @@
|
|||
<!-- Thanks for filling an issue!
|
||||
### Actual Result / Problem
|
||||
|
||||
If this is a BUG REPORT, please:
|
||||
- Fill in as much of the template below as you can
|
||||
When I do Foo, Bar happens...
|
||||
|
||||
If this is a FEATURE REQUEST, please:
|
||||
- Describe *in detail* the feature/behavior/change you would like to see
|
||||
-->
|
||||
### Expected Result / Suggestion
|
||||
|
||||
**What happened**:
|
||||
I expect that Foobar happens...
|
||||
|
||||
**What you expected to happen**:
|
||||
### Some context
|
||||
|
||||
**How to reproduce it (as minimally and precisely as possible)**:
|
||||
|
||||
**Anything else we need to know?**:
|
||||
|
||||
<!--
|
||||
**Environment**:
|
||||
- sshportal --version
|
||||
- ssh sshportal info
|
||||
- OS (e.g. from /etc/os-release):
|
||||
- install method (e.g. go/docker/brew/...):
|
||||
- others:
|
||||
-->
|
||||
Any screenshot to share?
|
||||
`sshportal --version`?
|
||||
`ssh sshportal info`?
|
||||
OS/Go version?
|
||||
...
|
||||
|
|
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -1,7 +1 @@
|
|||
<!-- Thanks for sending a pull request! Here are some tips for you -->
|
||||
|
||||
**What this PR does / why we need it**:
|
||||
|
||||
**Which issue this PR fixes**: fixes #xxx, fixes #xxx...
|
||||
|
||||
**Special notes for your reviewer**:
|
||||
<!-- thank you for your contribution! ❤️ -->
|
||||
|
|
20
.github/dependabot.yml
vendored
Normal file
20
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: docker
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
- package-ecosystem: gomod
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
19
.github/workflows/ci.yml
vendored
19
.github/workflows/ci.yml
vendored
|
@ -20,7 +20,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: lint
|
||||
uses: golangci/golangci-lint-action@v0.1.7
|
||||
uses: golangci/golangci-lint-action@v2.5.1
|
||||
with:
|
||||
version: v1.28
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
@ -30,7 +30,7 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
golang:
|
||||
- 1.15.0
|
||||
- 1.16.x
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Go
|
||||
|
@ -46,14 +46,14 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
golang:
|
||||
- 1.15.0
|
||||
- 1.16.x
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.golang }}
|
||||
- uses: actions/cache@v1
|
||||
- uses: actions/cache@v2.1.4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ matrix.golang }}-${{ hashFiles('**/go.sum') }}
|
||||
|
@ -67,18 +67,17 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
golang:
|
||||
- 1.11
|
||||
- 1.12
|
||||
- 1.13
|
||||
- 1.14
|
||||
- 1.15.0
|
||||
- 1.13.x
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
- 1.16.x
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.golang }}
|
||||
- uses: actions/cache@v1
|
||||
- uses: actions/cache@v2.1.4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ matrix.golang }}-${{ hashFiles('**/go.sum') }}
|
||||
|
|
6
AUTHORS
generated
6
AUTHORS
generated
|
@ -5,18 +5,23 @@ ahh <ahamidullah@gmail.com>
|
|||
Alen Masic <alenn.masic@gmail.com>
|
||||
Alexander Turner <me@alexturner.co>
|
||||
bozzo <bozzo@users.noreply.github.com>
|
||||
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
||||
fossabot <badges@fossa.io>
|
||||
ImgBotApp <ImgBotHelp@gmail.com>
|
||||
Jason Wessel <jason.wessel@windriver.com>
|
||||
Jean-Louis Férey <jeanlouis.ferey@orange.com>
|
||||
jerard@alfa-safety.fr <jrrdev@users.noreply.github.com>
|
||||
Jess <jessachandler@gmail.com>
|
||||
Jonathan Lestrelin <jonathan.lestrelin@gmail.com>
|
||||
Julien Dessaux <julien.dessaux@adyxax.org>
|
||||
Konstantin Bakaras <k.bakaras@voskhod.ru>
|
||||
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>
|
||||
matteyeux <matteyeux@users.noreply.github.com>
|
||||
Mikael Rapp <micke.rapp@gmail.com>
|
||||
MitaliBo <mitali.bisht14@gmail.com>
|
||||
moul-bot <bot@moul.io>
|
||||
|
@ -24,6 +29,7 @@ Nelly Asher <karmelylle@rambler.ru>
|
|||
NocFlame <aad@nocflame.se>
|
||||
Quentin Perez <qperez42@gmail.com>
|
||||
Renovate Bot <bot@renovateapp.com>
|
||||
Sergey Yashchuk <sergey.yashchuk@coins.ph>
|
||||
Shawn Wang <shawn111@gmail.com>
|
||||
Valentin Daviot <valentin.daviot@alterway.fr>
|
||||
valentin.daviot <valentin.daviot@alterway.fr>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# build
|
||||
FROM golang:1.15.2 as builder
|
||||
FROM golang:1.16.2 as builder
|
||||
ENV GO111MODULE=on
|
||||
WORKDIR /go/src/moul.io/sshportal
|
||||
COPY go.mod go.sum ./
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -186,7 +186,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2017 Manfred Touron <m@42.am>
|
||||
Copyright 2017-2021 Manfred Touron <m@42.am>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -366,7 +366,7 @@ user update [-h] [--name=<value>] [--email=<value>] [--set-admin] [--unset-admin
|
|||
|
||||
# usergroup management
|
||||
usergroup help
|
||||
hostgroup create [-h] [--name=<value>] [--comment=<value>]
|
||||
usergroup create [-h] [--name=<value>] [--comment=<value>]
|
||||
usergroup inspect [-h] USERGROUP...
|
||||
usergroup ls [-h] [--latest] [--quiet]
|
||||
usergroup rm [-h] USERGROUP...
|
||||
|
|
128
depaware.txt
Normal file
128
depaware.txt
Normal file
|
@ -0,0 +1,128 @@
|
|||
moul.io/sshportal dependencies: (generated by github.com/tailscale/depaware)
|
||||
|
||||
github.com/anmitsu/go-shlex from github.com/gliderlabs/ssh+
|
||||
github.com/asaskevich/govalidator from moul.io/sshportal/pkg/bastion+
|
||||
github.com/cpuguy83/go-md2man/v2/md2man from github.com/urfave/cli
|
||||
LD 💣 github.com/creack/pty from github.com/kr/pty
|
||||
github.com/docker/docker/pkg/namesgenerator from moul.io/sshportal/pkg/bastion
|
||||
github.com/docker/docker/pkg/random from github.com/docker/docker/pkg/namesgenerator
|
||||
github.com/dustin/go-humanize from moul.io/sshportal/pkg/bastion
|
||||
github.com/gliderlabs/ssh from moul.io/sshportal+
|
||||
github.com/go-sql-driver/mysql from github.com/jinzhu/gorm/dialects/mysql+
|
||||
github.com/jinzhu/gorm from gopkg.in/gormigrate.v1+
|
||||
github.com/jinzhu/gorm/dialects/mysql from moul.io/sshportal
|
||||
github.com/jinzhu/gorm/dialects/postgres from moul.io/sshportal
|
||||
github.com/jinzhu/gorm/dialects/sqlite from moul.io/sshportal
|
||||
github.com/jinzhu/inflection from github.com/jinzhu/gorm
|
||||
LD github.com/kr/pty from moul.io/sshportal
|
||||
github.com/lib/pq from github.com/jinzhu/gorm/dialects/postgres
|
||||
github.com/lib/pq/hstore from github.com/jinzhu/gorm/dialects/postgres
|
||||
github.com/lib/pq/oid from github.com/lib/pq
|
||||
github.com/lib/pq/scram from github.com/lib/pq
|
||||
💣 github.com/mattn/go-colorable from github.com/mgutz/ansi
|
||||
💣 github.com/mattn/go-isatty from github.com/mattn/go-colorable
|
||||
github.com/mattn/go-runewidth from github.com/olekukonko/tablewriter
|
||||
💣 github.com/mattn/go-sqlite3 from github.com/jinzhu/gorm/dialects/sqlite
|
||||
github.com/mgutz/ansi from moul.io/sshportal/pkg/bastion
|
||||
github.com/olekukonko/tablewriter from moul.io/sshportal/pkg/bastion
|
||||
github.com/pkg/errors from moul.io/sshportal/pkg/bastion
|
||||
github.com/reiver/go-oi from github.com/reiver/go-telnet+
|
||||
github.com/reiver/go-telnet from moul.io/sshportal/pkg/bastion
|
||||
github.com/russross/blackfriday/v2 from github.com/cpuguy83/go-md2man/v2/md2man
|
||||
github.com/sabban/bastion/pkg/logchannel from moul.io/sshportal/pkg/bastion
|
||||
github.com/shurcooL/sanitized_anchor_name from github.com/russross/blackfriday/v2
|
||||
github.com/urfave/cli from moul.io/sshportal+
|
||||
gopkg.in/gormigrate.v1 from moul.io/sshportal/pkg/bastion
|
||||
moul.io/srand from moul.io/sshportal
|
||||
moul.io/sshportal/pkg/bastion from moul.io/sshportal
|
||||
moul.io/sshportal/pkg/crypto from moul.io/sshportal/pkg/bastion
|
||||
moul.io/sshportal/pkg/dbmodels from moul.io/sshportal/pkg/bastion+
|
||||
golang.org/x/crypto/blowfish from golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
|
||||
golang.org/x/crypto/chacha20 from golang.org/x/crypto/chacha20poly1305+
|
||||
golang.org/x/crypto/chacha20poly1305 from crypto/tls
|
||||
golang.org/x/crypto/cryptobyte from crypto/ecdsa+
|
||||
golang.org/x/crypto/cryptobyte/asn1 from crypto/ecdsa+
|
||||
golang.org/x/crypto/curve25519 from crypto/tls+
|
||||
golang.org/x/crypto/ed25519 from golang.org/x/crypto/ssh
|
||||
golang.org/x/crypto/hkdf from crypto/tls
|
||||
golang.org/x/crypto/poly1305 from golang.org/x/crypto/chacha20poly1305+
|
||||
golang.org/x/crypto/ssh from github.com/gliderlabs/ssh+
|
||||
golang.org/x/crypto/ssh/terminal from moul.io/sshportal/pkg/bastion
|
||||
golang.org/x/net/dns/dnsmessage from net
|
||||
D golang.org/x/net/route from net
|
||||
golang.org/x/sys/cpu from golang.org/x/crypto/chacha20poly1305
|
||||
LD golang.org/x/sys/unix from github.com/mattn/go-isatty+
|
||||
W golang.org/x/sys/windows from golang.org/x/crypto/ssh/terminal
|
||||
bufio from crypto/rand+
|
||||
bytes from bufio+
|
||||
container/list from crypto/tls
|
||||
context from crypto/tls+
|
||||
crypto from crypto/ecdsa+
|
||||
crypto/aes from crypto/ecdsa+
|
||||
crypto/cipher from crypto/aes+
|
||||
crypto/des from crypto/tls+
|
||||
crypto/dsa from crypto/x509+
|
||||
crypto/ecdsa from crypto/tls+
|
||||
crypto/ed25519 from crypto/tls+
|
||||
crypto/elliptic from crypto/ecdsa+
|
||||
crypto/hmac from crypto/tls+
|
||||
crypto/md5 from crypto/tls+
|
||||
crypto/rand from crypto/ed25519+
|
||||
crypto/rc4 from crypto/tls+
|
||||
crypto/rsa from crypto/tls+
|
||||
crypto/sha1 from crypto/tls+
|
||||
crypto/sha256 from crypto/tls+
|
||||
crypto/sha512 from crypto/ecdsa+
|
||||
crypto/subtle from crypto/aes+
|
||||
crypto/tls from github.com/go-sql-driver/mysql+
|
||||
crypto/x509 from crypto/tls+
|
||||
crypto/x509/pkix from crypto/x509
|
||||
database/sql from github.com/go-sql-driver/mysql+
|
||||
database/sql/driver from database/sql+
|
||||
encoding from encoding/json
|
||||
encoding/asn1 from crypto/x509+
|
||||
encoding/base64 from encoding/json+
|
||||
encoding/binary from crypto/aes+
|
||||
encoding/csv from github.com/olekukonko/tablewriter
|
||||
encoding/hex from crypto/x509+
|
||||
encoding/json from github.com/asaskevich/govalidator+
|
||||
encoding/pem from crypto/tls+
|
||||
errors from bufio+
|
||||
flag from github.com/urfave/cli
|
||||
fmt from crypto/tls+
|
||||
go/ast from github.com/jinzhu/gorm
|
||||
go/scanner from go/ast
|
||||
go/token from go/ast+
|
||||
hash from crypto+
|
||||
html from github.com/asaskevich/govalidator+
|
||||
io from bufio+
|
||||
io/fs from crypto/rand+
|
||||
io/ioutil from crypto/x509+
|
||||
log from github.com/gliderlabs/ssh+
|
||||
math from crypto/rsa+
|
||||
math/big from crypto/dsa+
|
||||
math/bits from crypto/md5+
|
||||
math/rand from github.com/docker/docker/pkg/random+
|
||||
net from crypto/tls+
|
||||
net/url from crypto/x509+
|
||||
os from crypto/rand+
|
||||
LD os/exec from github.com/creack/pty+
|
||||
os/user from github.com/lib/pq+
|
||||
path from github.com/asaskevich/govalidator+
|
||||
path/filepath from crypto/x509+
|
||||
reflect from crypto/x509+
|
||||
regexp from github.com/asaskevich/govalidator+
|
||||
regexp/syntax from regexp
|
||||
sort from database/sql+
|
||||
strconv from crypto+
|
||||
strings from bufio+
|
||||
sync from context+
|
||||
sync/atomic from context+
|
||||
syscall from crypto/rand+
|
||||
text/tabwriter from github.com/urfave/cli
|
||||
text/template from github.com/urfave/cli
|
||||
text/template/parse from text/template
|
||||
time from context+
|
||||
unicode from bytes+
|
||||
unicode/utf16 from encoding/asn1+
|
||||
unicode/utf8 from bufio+
|
26
go.mod
generated
26
go.mod
generated
|
@ -2,33 +2,27 @@ module moul.io/sshportal
|
|||
|
||||
require (
|
||||
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.11 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef
|
||||
github.com/docker/docker v1.13.1
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/gliderlabs/ssh v0.3.0
|
||||
github.com/gliderlabs/ssh v0.3.2
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
|
||||
github.com/jinzhu/gorm v1.9.15
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/kr/pty v1.1.8
|
||||
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/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/pkg/errors v0.9.1
|
||||
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
|
||||
github.com/urfave/cli v1.22.4
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect
|
||||
github.com/tailscale/depaware v0.0.0-20201214215404-77d1e9757027
|
||||
github.com/urfave/cli v1.22.5
|
||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9
|
||||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58
|
||||
gopkg.in/gormigrate.v1 v1.6.0
|
||||
moul.io/srand v1.4.0
|
||||
moul.io/srand v1.6.1
|
||||
)
|
||||
|
||||
go 1.14
|
||||
|
|
85
go.sum
generated
85
go.sum
generated
|
@ -4,17 +4,14 @@ github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBK
|
|||
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/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
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.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
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=
|
||||
|
@ -24,8 +21,8 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4
|
|||
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/gliderlabs/ssh v0.3.0 h1:7GcKy4erEljCE/QeQ2jTVpu+3f3zkpZOxOJjFYkMqYU=
|
||||
github.com/gliderlabs/ssh v0.3.0/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/gliderlabs/ssh v0.3.2 h1:gcfd1Aj/9RQxvygu4l3sak711f/5+VOwBw9C/7+N4EI=
|
||||
github.com/gliderlabs/ssh v0.3.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
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=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
|
@ -34,12 +31,11 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZ
|
|||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
|
||||
github.com/jinzhu/gorm v1.9.15 h1:OdR1qFvtXktlxk73XFYMiYn9ywzTwytqe4QkuMRqc38=
|
||||
github.com/jinzhu/gorm v1.9.15/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
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=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
|
@ -55,21 +51,21 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
|||
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.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/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.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/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
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-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7 h1:+/+DxvQaYifJ+grD4klzrS5y+KJXldn/2YTl5JG+vZ8=
|
||||
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
|
@ -82,43 +78,68 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
|
|||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sabban/bastion v0.0.0-20180110125408-b9d3c9b1f4d3 h1:yxUGvEatvDMO6gkhwx82Va+Czdyui9LiCw6a5YB/2f8=
|
||||
github.com/sabban/bastion v0.0.0-20180110125408-b9d3c9b1f4d3/go.mod h1:1Q04m7wmv/IMoZU9t8UkH+n9McWn4i3H9v9LnMgqloo=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
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 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.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
|
||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tailscale/depaware v0.0.0-20201214215404-77d1e9757027 h1:lK99QQdH3yBWY6aGilF+IRlQIdmhzLrsEmF6JgN+Ryw=
|
||||
github.com/tailscale/depaware v0.0.0-20201214215404-77d1e9757027/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
|
||||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 h1:umElSU9WZirRdgu2yFHY0ayQkEnKiOC1TtM3fWXFnoU=
|
||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-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/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58 h1:1Bs6RVeBFtLZ8Yi1Hk07DiOqzvwLD/4hln4iahvFlag=
|
||||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/gormigrate.v1 v1.6.0 h1:XpYM6RHQPmzwY7Uyu+t+xxMXc86JYFJn4nEc9HzQjsI=
|
||||
gopkg.in/gormigrate.v1 v1.6.0/go.mod h1:Lf00lQrHqfSYWiTtPcyQabsDdM6ejZaMgV0OU6JMSlw=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
moul.io/srand v1.4.0 h1:r5ZMiWDN0ni0lTV7KzJR/jx0K7GivJYW5WaXmufgeik=
|
||||
moul.io/srand v1.4.0/go.mod h1:P2uaZB+GFstFNo8sEj6/U8FRV1n25kD0LLckFpJ+qvc=
|
||||
moul.io/srand v1.6.1 h1:SJ335F+54ivLdlH7wH52Rtyv0Ffos6DpsF5wu3ZVMXU=
|
||||
moul.io/srand v1.6.1/go.mod h1:P2uaZB+GFstFNo8sEj6/U8FRV1n25kD0LLckFpJ+qvc=
|
||||
|
|
11
internal/tools/tools.go
Normal file
11
internal/tools/tools.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
// +build tools
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
// required by depaware
|
||||
_ "github.com/tailscale/depaware/depaware"
|
||||
|
||||
// required by goimports
|
||||
_ "golang.org/x/tools/cover"
|
||||
)
|
2
main.go
2
main.go
|
@ -22,7 +22,7 @@ var (
|
|||
)
|
||||
|
||||
func main() {
|
||||
rand.Seed(srand.Secure())
|
||||
rand.Seed(srand.MustSecure())
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = path.Base(os.Args[0])
|
||||
|
|
|
@ -537,7 +537,7 @@ func DBInit(db *gorm.DB) error {
|
|||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
key, err := crypto.NewSSHKey("rsa", 2048)
|
||||
key, err := crypto.NewSSHKey("ed25519", 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -644,7 +644,7 @@ func DBInit(db *gorm.DB) error {
|
|||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
key, err := crypto.NewSSHKey("rsa", 2048)
|
||||
key, err := crypto.NewSSHKey("ed25519", 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
|
@ -24,6 +25,7 @@ import (
|
|||
"golang.org/x/crypto/ssh/terminal"
|
||||
"moul.io/sshportal/pkg/crypto"
|
||||
"moul.io/sshportal/pkg/dbmodels"
|
||||
"moul.io/sshportal/pkg/utils"
|
||||
)
|
||||
|
||||
var banner = `
|
||||
|
@ -510,7 +512,6 @@ GLOBAL OPTIONS:
|
|||
"host_groups",
|
||||
"host_host_groups",
|
||||
"hosts",
|
||||
//"migrations",
|
||||
"sessions",
|
||||
"settings",
|
||||
"ssh_keys",
|
||||
|
@ -521,6 +522,7 @@ GLOBAL OPTIONS:
|
|||
"user_user_groups",
|
||||
"user_user_roles",
|
||||
"users",
|
||||
// "migrations",
|
||||
}
|
||||
for _, tableName := range tableNames {
|
||||
/* #nosec */
|
||||
|
@ -828,12 +830,14 @@ GLOBAL OPTIONS:
|
|||
}
|
||||
|
||||
var hosts []*dbmodels.Host
|
||||
db = db.Preload("Groups")
|
||||
if myself.HasRole("admin") {
|
||||
db = db.Preload("SSHKey")
|
||||
}
|
||||
if err := dbmodels.HostsByIdentifiers(db, c.Args()).Find(&hosts).Error; err != nil {
|
||||
return err
|
||||
if err := dbmodels.HostsByIdentifiers(db.Preload("Groups").Preload("SSHKey"), c.Args()).Find(&hosts).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := dbmodels.HostsByIdentifiers(db.Preload("Groups"), c.Args()).Find(&hosts).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if c.Bool("decrypt") {
|
||||
|
@ -1276,8 +1280,8 @@ GLOBAL OPTIONS:
|
|||
Description: "$> key create\n $> key create --name=mykey",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "name", Usage: "Assigns a name to the key"},
|
||||
cli.StringFlag{Name: "type", Value: "rsa"},
|
||||
cli.UintFlag{Name: "length", Value: 2048},
|
||||
cli.StringFlag{Name: "type", Value: "ed25519"},
|
||||
cli.UintFlag{Name: "length", Value: 0},
|
||||
cli.StringFlag{Name: "comment", Usage: "Adds a comment"},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
|
@ -1290,7 +1294,24 @@ GLOBAL OPTIONS:
|
|||
name = c.String("name")
|
||||
}
|
||||
|
||||
key, err := crypto.NewSSHKey(c.String("type"), c.Uint("length"))
|
||||
length := c.Uint("length")
|
||||
if length == 0 {
|
||||
switch c.String("type") {
|
||||
case "rsa":
|
||||
// same default as ssh-keygen
|
||||
length = 3072
|
||||
case "ecdsa":
|
||||
// same default as ssh-keygen
|
||||
length = 256
|
||||
case "ed25519":
|
||||
// irrelevant for ed25519
|
||||
// set it to 1 to enforce consistency
|
||||
// and because 0 is invalid
|
||||
length = 1
|
||||
}
|
||||
}
|
||||
|
||||
key, err := crypto.NewSSHKey(c.String("type"), length)
|
||||
if actx.aesKey != "" {
|
||||
if err2 := crypto.SSHKeyEncrypt(actx.aesKey, key); err2 != nil {
|
||||
return err2
|
||||
|
@ -1439,7 +1460,6 @@ GLOBAL OPTIONS:
|
|||
key.Name,
|
||||
key.Type,
|
||||
fmt.Sprintf("%d", key.Length),
|
||||
//key.Fingerprint,
|
||||
fmt.Sprintf("%d", len(key.Hosts)),
|
||||
humanize.Time(key.UpdatedAt),
|
||||
humanize.Time(key.CreatedAt),
|
||||
|
@ -1604,9 +1624,11 @@ GLOBAL OPTIONS:
|
|||
return err
|
||||
}
|
||||
|
||||
// FIXME: validate email
|
||||
|
||||
email := c.Args().First()
|
||||
valid := utils.ValidateEmail(email)
|
||||
if !valid {
|
||||
return errors.New("invalid email")
|
||||
}
|
||||
name := strings.Split(email, "@")[0]
|
||||
if c.String("name") != "" {
|
||||
name = c.String("name")
|
||||
|
@ -1719,6 +1741,8 @@ GLOBAL OPTIONS:
|
|||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "name, n", Usage: "Renames the user"},
|
||||
cli.StringFlag{Name: "email, e", Usage: "Updates the email"},
|
||||
cli.StringFlag{Name: "invite_token, i", Usage: "Updates the invite token"},
|
||||
cli.BoolFlag{Name: "remove_invite, R", Usage: "Remove invite token"},
|
||||
cli.StringSliceFlag{Name: "assign-role, r", Usage: "Assign the user to new `USERROLES`"},
|
||||
cli.StringSliceFlag{Name: "unassign-role", Usage: "Unassign the user from `USERROLES`"},
|
||||
cli.StringSliceFlag{Name: "assign-group, g", Usage: "Assign the user to new `USERGROUPS`"},
|
||||
|
@ -1751,7 +1775,7 @@ GLOBAL OPTIONS:
|
|||
for _, user := range users {
|
||||
model := tx.Model(user)
|
||||
// simple fields
|
||||
for _, fieldname := range []string{"name", "email", "comment"} {
|
||||
for _, fieldname := range []string{"name", "email", "comment", "invite_token"} {
|
||||
if c.String(fieldname) != "" {
|
||||
if err := model.Update(fieldname, c.String(fieldname)).Error; err != nil {
|
||||
tx.Rollback()
|
||||
|
@ -1759,6 +1783,13 @@ GLOBAL OPTIONS:
|
|||
}
|
||||
}
|
||||
}
|
||||
// invite remove
|
||||
if c.Bool("remove_invite") {
|
||||
if err := model.Update("invite_token", "").Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// associations
|
||||
var appendGroups []dbmodels.UserGroup
|
||||
|
@ -2000,34 +2031,58 @@ GLOBAL OPTIONS:
|
|||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(s, "Enter key:\n")
|
||||
reader := bufio.NewReader(s)
|
||||
text, _ := reader.ReadString('\n')
|
||||
|
||||
key, comment, _, _, err := ssh.ParseAuthorizedKey([]byte(text))
|
||||
if err != nil {
|
||||
return err
|
||||
var reader *bufio.Reader
|
||||
var term *terminal.Terminal
|
||||
if len(sshCommand) == 0 { // interactive mode
|
||||
term = terminal.NewTerminal(s, "Paste your key(s) and end with a blank line> ")
|
||||
} else {
|
||||
fmt.Fprintf(s, "Enter key(s):\n")
|
||||
reader = bufio.NewReader(s)
|
||||
}
|
||||
|
||||
userkey := dbmodels.UserKey{
|
||||
User: &user,
|
||||
Key: key.Marshal(),
|
||||
Comment: comment,
|
||||
AuthorizedKey: string(gossh.MarshalAuthorizedKey(key)),
|
||||
}
|
||||
if c.String("comment") != "" {
|
||||
userkey.Comment = c.String("comment")
|
||||
}
|
||||
for {
|
||||
var text string
|
||||
var errReadline error
|
||||
if len(sshCommand) == 0 { // interactive mode
|
||||
text, errReadline = term.ReadLine()
|
||||
} else {
|
||||
text, errReadline = reader.ReadString('\n')
|
||||
}
|
||||
if errReadline != nil && errReadline != io.EOF {
|
||||
return errReadline
|
||||
}
|
||||
if text != "" && text != "\n" {
|
||||
key, comment, _, _, err := ssh.ParseAuthorizedKey([]byte(text))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := govalidator.ValidateStruct(userkey); err != nil {
|
||||
return err
|
||||
}
|
||||
userkey := dbmodels.UserKey{
|
||||
User: &user,
|
||||
Key: key.Marshal(),
|
||||
Comment: comment,
|
||||
AuthorizedKey: string(gossh.MarshalAuthorizedKey(key)),
|
||||
}
|
||||
if c.String("comment") != "" {
|
||||
userkey.Comment = c.String("comment")
|
||||
}
|
||||
|
||||
// save the userkey in database
|
||||
if err := db.Create(&userkey).Error; err != nil {
|
||||
return err
|
||||
if _, err := govalidator.ValidateStruct(userkey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// save the userkey in database
|
||||
if err := db.Create(&userkey).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(s, "%d\n", userkey.ID)
|
||||
if errReadline == io.EOF {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(s, "%d\n", userkey.ID)
|
||||
return nil
|
||||
},
|
||||
}, {
|
||||
|
@ -2115,7 +2170,16 @@ GLOBAL OPTIONS:
|
|||
if err := myself.CheckRoles([]string{"admin"}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := dbmodels.UserKeysByIdentifiers(db, c.Args()).Find(&dbmodels.UserKey{}).Error; err != nil {
|
||||
var user dbmodels.User
|
||||
if err := dbmodels.UsersByIdentifiers(db, c.Args()).First(&user).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := dbmodels.UserKeysByUserID(db, []string{fmt.Sprint(user.ID)}).Find(&dbmodels.UserKey{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return dbmodels.UserKeysByUserID(db, []string{fmt.Sprint(user.ID)}).Delete(&dbmodels.UserKey{}).Error
|
||||
}
|
||||
return dbmodels.UserKeysByIdentifiers(db, c.Args()).Delete(&dbmodels.UserKey{}).Error
|
||||
},
|
||||
},
|
||||
|
@ -2276,7 +2340,7 @@ GLOBAL OPTIONS:
|
|||
if cliErr.ExitCode() != 0 {
|
||||
fmt.Fprintf(s, "error: %v\n", err)
|
||||
}
|
||||
//s.Exit(cliErr.ExitCode())
|
||||
// s.Exit(cliErr.ExitCode())
|
||||
} else {
|
||||
fmt.Fprintf(s, "error: %v\n", err)
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ func scannerSplitFunc(data []byte, atEOF bool) (advance int, token []byte, err e
|
|||
func telnetHandler(host *dbmodels.Host) ssh.Handler {
|
||||
return func(s ssh.Session) {
|
||||
// FIXME: log session in db
|
||||
//actx := s.Context().Value(authContextKey).(*authContext)
|
||||
// actx := s.Context().Value(authContextKey).(*authContext)
|
||||
caller := bastionTelnetCaller{ssh: s}
|
||||
if err := telnet.DialToAndCall(host.DialAddr(), caller); err != nil {
|
||||
fmt.Fprintf(s, "error: %v", err)
|
||||
|
|
|
@ -4,6 +4,9 @@ import (
|
|||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
|
@ -25,35 +28,108 @@ func NewSSHKey(keyType string, length uint) (*dbmodels.SSHKey, error) {
|
|||
}
|
||||
|
||||
// generate the private key
|
||||
if keyType != "rsa" {
|
||||
return nil, fmt.Errorf("key type not supported: %q", key.Type)
|
||||
var err error
|
||||
var pemKey *pem.Block
|
||||
var publicKey gossh.PublicKey
|
||||
switch keyType {
|
||||
case "rsa":
|
||||
pemKey, publicKey, err = NewRSAKey(length)
|
||||
case "ecdsa":
|
||||
pemKey, publicKey, err = NewECDSAKey(length)
|
||||
case "ed25519":
|
||||
pemKey, publicKey, err = NewEd25519Key()
|
||||
default:
|
||||
return nil, fmt.Errorf("key type not supported: %q, supported types are: rsa, ecdsa, ed25519", key.Type)
|
||||
}
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// convert priv key to x509 format
|
||||
var pemKey = &pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
|
||||
}
|
||||
buf := bytes.NewBufferString("")
|
||||
if err = pem.Encode(buf, pemKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key.PrivKey = buf.String()
|
||||
|
||||
// generte authorized-key formatted pubkey output
|
||||
pub, err := gossh.NewPublicKey(&privateKey.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key.PubKey = strings.TrimSpace(string(gossh.MarshalAuthorizedKey(pub)))
|
||||
// generate authorized-key formatted pubkey output
|
||||
key.PubKey = strings.TrimSpace(string(gossh.MarshalAuthorizedKey(publicKey)))
|
||||
|
||||
return &key, nil
|
||||
}
|
||||
|
||||
func NewRSAKey(length uint) (*pem.Block, gossh.PublicKey, error) {
|
||||
if length < 1024 || length > 16384 {
|
||||
return nil, nil, fmt.Errorf("key length not supported: %d, supported values are between 1024 and 16384", length)
|
||||
}
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, int(length))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// convert priv key to x509 format
|
||||
pemKey := &pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
|
||||
}
|
||||
publicKey, err := gossh.NewPublicKey(&privateKey.PublicKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return pemKey, publicKey, err
|
||||
}
|
||||
|
||||
func NewECDSAKey(length uint) (*pem.Block, gossh.PublicKey, error) {
|
||||
var curve elliptic.Curve
|
||||
switch length {
|
||||
case 256:
|
||||
curve = elliptic.P256()
|
||||
case 384:
|
||||
curve = elliptic.P384()
|
||||
case 521:
|
||||
curve = elliptic.P521()
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("key length not supported: %d, supported values are 256, 384, 521", length)
|
||||
}
|
||||
privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// convert priv key to x509 format
|
||||
marshaledKey, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||||
pemKey := &pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: marshaledKey,
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
publicKey, err := gossh.NewPublicKey(&privateKey.PublicKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return pemKey, publicKey, err
|
||||
}
|
||||
|
||||
func NewEd25519Key() (*pem.Block, gossh.PublicKey, error) {
|
||||
publicKeyEd25519, privateKey, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// convert priv key to x509 format
|
||||
marshaledKey, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||||
pemKey := &pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: marshaledKey,
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
publicKey, err := gossh.NewPublicKey(publicKeyEd25519)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return pemKey, publicKey, err
|
||||
}
|
||||
|
||||
func ImportSSHKey(keyValue string) (*dbmodels.SSHKey, error) {
|
||||
key := dbmodels.SSHKey{
|
||||
Type: "rsa",
|
||||
|
|
|
@ -167,6 +167,25 @@ const (
|
|||
BastionSchemeTelnet BastionScheme = "telnet"
|
||||
)
|
||||
|
||||
// Generic Helper
|
||||
func GenericNameOrID(db *gorm.DB, identifiers []string) *gorm.DB {
|
||||
var ids []string
|
||||
var names []string
|
||||
for _, s := range identifiers {
|
||||
if _, err := strconv.Atoi(s); err == nil {
|
||||
ids = append(ids, s)
|
||||
} else {
|
||||
names = append(names, s)
|
||||
}
|
||||
}
|
||||
if len(ids) > 0 && len(names) > 0 {
|
||||
return db.Where("id IN (?)", ids).Or("name IN (?)", names)
|
||||
} else if len(ids) > 0 {
|
||||
return db.Where("id IN (?)", ids)
|
||||
}
|
||||
return db.Where("name IN (?)", names)
|
||||
}
|
||||
|
||||
// Host helpers
|
||||
|
||||
func (host *Host) DialAddr() string {
|
||||
|
@ -268,7 +287,7 @@ func HostsPreload(db *gorm.DB) *gorm.DB {
|
|||
return db.Preload("Groups").Preload("SSHKey")
|
||||
}
|
||||
func HostsByIdentifiers(db *gorm.DB, identifiers []string) *gorm.DB {
|
||||
return db.Where("id IN (?)", identifiers).Or("name IN (?)", identifiers)
|
||||
return GenericNameOrID(db, identifiers)
|
||||
}
|
||||
func HostByName(db *gorm.DB, name string) (*Host, error) {
|
||||
var host Host
|
||||
|
@ -308,7 +327,7 @@ func SSHKeysPreload(db *gorm.DB) *gorm.DB {
|
|||
return db.Preload("Hosts")
|
||||
}
|
||||
func SSHKeysByIdentifiers(db *gorm.DB, identifiers []string) *gorm.DB {
|
||||
return db.Where("id IN (?)", identifiers).Or("name IN (?)", identifiers)
|
||||
return GenericNameOrID(db, identifiers)
|
||||
}
|
||||
|
||||
// HostGroup helpers
|
||||
|
@ -317,7 +336,7 @@ func HostGroupsPreload(db *gorm.DB) *gorm.DB {
|
|||
return db.Preload("ACLs").Preload("Hosts")
|
||||
}
|
||||
func HostGroupsByIdentifiers(db *gorm.DB, identifiers []string) *gorm.DB {
|
||||
return db.Where("id IN (?)", identifiers).Or("name IN (?)", identifiers)
|
||||
return GenericNameOrID(db, identifiers)
|
||||
}
|
||||
|
||||
// UserGroup helpers
|
||||
|
@ -326,7 +345,7 @@ func UserGroupsPreload(db *gorm.DB) *gorm.DB {
|
|||
return db.Preload("ACLs").Preload("Users")
|
||||
}
|
||||
func UserGroupsByIdentifiers(db *gorm.DB, identifiers []string) *gorm.DB {
|
||||
return db.Where("id IN (?)", identifiers).Or("name IN (?)", identifiers)
|
||||
return GenericNameOrID(db, identifiers)
|
||||
}
|
||||
|
||||
// User helpers
|
||||
|
@ -335,7 +354,21 @@ func UsersPreload(db *gorm.DB) *gorm.DB {
|
|||
return db.Preload("Groups").Preload("Keys").Preload("Roles")
|
||||
}
|
||||
func UsersByIdentifiers(db *gorm.DB, identifiers []string) *gorm.DB {
|
||||
return db.Where("id IN (?)", identifiers).Or("email IN (?)", identifiers).Or("name IN (?)", identifiers)
|
||||
var ids []string
|
||||
var names []string
|
||||
for _, s := range identifiers {
|
||||
if _, err := strconv.Atoi(s); err == nil {
|
||||
ids = append(ids, s)
|
||||
} else {
|
||||
names = append(names, s)
|
||||
}
|
||||
}
|
||||
if len(ids) > 0 && len(names) > 0 {
|
||||
db.Where("id IN (?)", identifiers).Or("email IN (?)", identifiers).Or("name IN (?)", identifiers)
|
||||
} else if len(ids) > 0 {
|
||||
return db.Where("id IN (?)", ids)
|
||||
}
|
||||
return db.Where("email IN (?)", identifiers).Or("name IN (?)", identifiers)
|
||||
}
|
||||
func (u *User) HasRole(name string) bool {
|
||||
for _, role := range u.Roles {
|
||||
|
@ -371,14 +404,14 @@ func UserKeysPreload(db *gorm.DB) *gorm.DB {
|
|||
func UserKeysByIdentifiers(db *gorm.DB, identifiers []string) *gorm.DB {
|
||||
return db.Where("id IN (?)", identifiers)
|
||||
}
|
||||
func UserKeysByUserID(db *gorm.DB, identifiers []string) *gorm.DB {
|
||||
return db.Where("user_id IN (?)", identifiers)
|
||||
}
|
||||
|
||||
// UserRole helpers
|
||||
|
||||
//func UserRolesPreload(db *gorm.DB) *gorm.DB {
|
||||
// return db.Preload("Users")
|
||||
//}
|
||||
func UserRolesByIdentifiers(db *gorm.DB, identifiers []string) *gorm.DB {
|
||||
return db.Where("id IN (?)", identifiers).Or("name IN (?)", identifiers)
|
||||
return GenericNameOrID(db, identifiers)
|
||||
}
|
||||
|
||||
// Session helpers
|
||||
|
@ -425,7 +458,6 @@ func (e *Event) Log(db *gorm.DB) {
|
|||
}
|
||||
|
||||
func (e *Event) SetAuthor(user *User) *Event {
|
||||
//e.Author = user
|
||||
e.AuthorID = user.ID
|
||||
return e
|
||||
}
|
||||
|
|
13
pkg/utils/emailvalidator.go
Normal file
13
pkg/utils/emailvalidator.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package utils
|
||||
|
||||
import "regexp"
|
||||
|
||||
var emailRegex = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
||||
|
||||
// ValidateEmail validates email.
|
||||
func ValidateEmail(e string) bool {
|
||||
if len(e) < 3 && len(e) > 254 {
|
||||
return false
|
||||
}
|
||||
return emailRegex.MatchString(e)
|
||||
}
|
22
pkg/utils/emailvalidator_test.go
Normal file
22
pkg/utils/emailvalidator_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateEmail(t *testing.T) {
|
||||
|
||||
goodEmail := "goodemail@email.com"
|
||||
badEmail := "b@2323.22"
|
||||
|
||||
got := ValidateEmail(goodEmail)
|
||||
if got == false {
|
||||
t.Errorf("got1= %v; want true", got)
|
||||
}
|
||||
|
||||
got2 := ValidateEmail(badEmail)
|
||||
if got2 == false {
|
||||
t.Errorf("got2= %v; want false", got2)
|
||||
}
|
||||
|
||||
}
|
68
rules.mk
vendored
68
rules.mk
vendored
|
@ -23,7 +23,8 @@
|
|||
# || | | | | | /_/_/_/\___/\_,_/_/ |
|
||||
# +--------------------------------------------------------------+
|
||||
|
||||
all: help
|
||||
.PHONY: _default_entrypoint
|
||||
_default_entrypoint: help
|
||||
|
||||
##
|
||||
## Common helpers
|
||||
|
@ -31,6 +32,8 @@ all: help
|
|||
|
||||
rwildcard = $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
|
||||
check-program = $(foreach exec,$(1),$(if $(shell PATH="$(PATH)" which $(exec)),,$(error "No $(exec) in PATH")))
|
||||
my-filter-out = $(foreach v,$(2),$(if $(findstring $(1),$(v)),,$(v)))
|
||||
novendor = $(call my-filter-out,vendor/,$(1))
|
||||
|
||||
##
|
||||
## rules.mk
|
||||
|
@ -71,7 +74,7 @@ GO ?= go
|
|||
GOPATH ?= $(HOME)/go
|
||||
GO_INSTALL_OPTS ?=
|
||||
GO_TEST_OPTS ?= -test.timeout=30s
|
||||
GOMOD_DIR ?= .
|
||||
GOMOD_DIRS ?= $(sort $(call novendor,$(dir $(call rwildcard,*,*/go.mod go.mod))))
|
||||
GOCOVERAGE_FILE ?= ./coverage.txt
|
||||
GOTESTJSON_FILE ?= ./go-test.json
|
||||
GOBUILDLOG_FILE ?= ./go-build.log
|
||||
|
@ -109,10 +112,11 @@ go.unittest:
|
|||
ifeq ($(CI),true)
|
||||
@echo "mode: atomic" > /tmp/gocoverage
|
||||
@rm -f $(GOTESTJSON_FILE)
|
||||
@set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do (set -e; (set -euf pipefail; \
|
||||
@set -e; for dir in $(GOMOD_DIRS); do (set -e; (set -euf pipefail; \
|
||||
cd $$dir; \
|
||||
($(GO) test ./... $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race -json | tee -a $(GOTESTJSON_FILE) 3>&1 1>&2 2>&3 | tee -a $(GOBUILDLOG_FILE); \
|
||||
(($(GO) test ./... $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race -json && touch $@.ok) | tee -a $(GOTESTJSON_FILE) 3>&1 1>&2 2>&3 | tee -a $(GOBUILDLOG_FILE); \
|
||||
); \
|
||||
rm $@.ok 2>/dev/null || exit 1; \
|
||||
if [ -f /tmp/profile.out ]; then \
|
||||
cat /tmp/profile.out | sed "/mode: atomic/d" >> /tmp/gocoverage; \
|
||||
rm -f /tmp/profile.out; \
|
||||
|
@ -120,7 +124,7 @@ ifeq ($(CI),true)
|
|||
@mv /tmp/gocoverage $(GOCOVERAGE_FILE)
|
||||
else
|
||||
@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; \
|
||||
@set -e; for dir in $(GOMOD_DIRS); 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 \
|
||||
|
@ -132,7 +136,7 @@ endif
|
|||
|
||||
.PHONY: go.checkdoc
|
||||
go.checkdoc:
|
||||
go doc $(GOMOD_DIR)
|
||||
go doc $(first $(GOMOD_DIRS))
|
||||
|
||||
.PHONY: go.coverfunc
|
||||
go.coverfunc: go.unittest
|
||||
|
@ -140,46 +144,74 @@ go.coverfunc: go.unittest
|
|||
|
||||
.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; \
|
||||
@set -e; for dir in $(GOMOD_DIRS); 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; \
|
||||
@# tidy dirs with go.mod files
|
||||
@set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \
|
||||
cd $$dir; \
|
||||
$(GO) mod tidy; \
|
||||
); done
|
||||
|
||||
.PHONY: go.depaware-update
|
||||
go.depaware-update: go.tidy
|
||||
@# gen depaware for bins
|
||||
@set -e; for dir in $(GOBINS); do ( set -xe; \
|
||||
cd $$dir; \
|
||||
$(GO) run github.com/tailscale/depaware --update .; \
|
||||
); done
|
||||
@# tidy unused depaware deps if not in a tools_test.go file
|
||||
@set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \
|
||||
cd $$dir; \
|
||||
$(GO) mod tidy; \
|
||||
); done
|
||||
|
||||
.PHONY: go.depaware-check
|
||||
go.depaware-check: go.tidy
|
||||
@# gen depaware for bins
|
||||
@set -e; for dir in $(GOBINS); do ( set -xe; \
|
||||
cd $$dir; \
|
||||
$(GO) run github.com/tailscale/depaware --check .; \
|
||||
); 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; \
|
||||
@set -e; for dir in $(GOMOD_DIRS); 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; \
|
||||
@set -e; for dir in $(GOMOD_DIRS); 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; \
|
||||
@set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \
|
||||
cd $$dir; \
|
||||
goimports -w `go list -f '{{.Dir}}' ./...)` \
|
||||
$(GO) run golang.org/x/tools/cmd/goimports -w `go list -f '{{.Dir}}' ./...` \
|
||||
); done
|
||||
|
||||
VERIFY_STEPS += go.depaware-check
|
||||
BUILD_STEPS += go.build
|
||||
BUMPDEPS_STEPS += go.bumpdeps
|
||||
BUMPDEPS_STEPS += go.bumpdeps go.depaware-update
|
||||
TIDY_STEPS += go.tidy
|
||||
LINT_STEPS += go.lint
|
||||
UNITTEST_STEPS += go.unittest
|
||||
FMT_STEPS += go.fmt
|
||||
|
||||
# FIXME: disabled, because currently slow
|
||||
# new rule that is manually run sometimes, i.e. `make pre-release` or `make maintenance`.
|
||||
# alternative: run it each time the go.mod is changed
|
||||
#GENERATE_STEPS += go.depaware-update
|
||||
endif
|
||||
|
||||
##
|
||||
|
@ -285,6 +317,11 @@ ifdef BUILD_STEPS
|
|||
build: $(PRE_BUILD_STEPS) $(BUILD_STEPS)
|
||||
endif
|
||||
|
||||
ifdef VERIFY_STEPS
|
||||
.PHONY: verify
|
||||
verify: $(PRE_VERIFY_STEPS) $(VERIFY_STEPS)
|
||||
endif
|
||||
|
||||
ifdef RELEASE_STEPS
|
||||
.PHONY: release
|
||||
release: $(PRE_RELEASE_STEPS) $(RELEASE_STEPS)
|
||||
|
@ -318,4 +355,7 @@ help::
|
|||
@[ "$(TEST_STEPS)" != "" ] && echo " test" || true
|
||||
@[ "$(TIDY_STEPS)" != "" ] && echo " tidy" || true
|
||||
@[ "$(UNITTEST_STEPS)" != "" ] && echo " unittest" || true
|
||||
@[ "$(VERIFY_STEPS)" != "" ] && echo " verify" || true
|
||||
@# FIXME: list other commands
|
||||
|
||||
print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
|
||||
|
|
|
@ -59,7 +59,7 @@ func ensureLogDirectory(location string) error {
|
|||
}
|
||||
|
||||
func server(c *serverConfig) (err error) {
|
||||
var db = (*gorm.DB)(nil)
|
||||
var db *gorm.DB
|
||||
|
||||
// try to setup the local DB
|
||||
if db, err = gorm.Open(c.dbDriver, c.dbURL); err != nil {
|
||||
|
|
|
@ -60,7 +60,7 @@ func testServer(c *cli.Context) error {
|
|||
_, _ = io.Copy(s, f) // #nosec
|
||||
cmdErr = cmd.Wait()
|
||||
} else {
|
||||
//cmd.Stdin = s
|
||||
// cmd.Stdin = s
|
||||
cmd.Stdout = s
|
||||
cmd.Stderr = s
|
||||
cmdErr = cmd.Run()
|
||||
|
|
Loading…
Reference in a new issue