2017-10-30 23:48:14 +08:00
|
|
|
package main
|
|
|
|
|
2017-10-31 16:24:18 +08:00
|
|
|
import (
|
|
|
|
"fmt"
|
2017-10-31 23:22:40 +08:00
|
|
|
"net/url"
|
|
|
|
"strings"
|
2017-10-30 23:48:14 +08:00
|
|
|
|
2017-10-31 16:24:18 +08:00
|
|
|
"github.com/gliderlabs/ssh"
|
|
|
|
"github.com/jinzhu/gorm"
|
|
|
|
)
|
|
|
|
|
|
|
|
type SSHKey struct {
|
2017-10-31 23:22:40 +08:00
|
|
|
// FIXME: use uuid for ID
|
2017-10-30 23:48:14 +08:00
|
|
|
gorm.Model
|
2017-11-01 22:48:30 +08:00
|
|
|
Name string // FIXME: govalidator: min length 3, alphanum
|
2017-10-31 16:24:18 +08:00
|
|
|
Type string
|
2017-11-01 22:48:30 +08:00
|
|
|
Length uint
|
2017-10-31 16:24:18 +08:00
|
|
|
Fingerprint string
|
2017-11-01 22:48:30 +08:00
|
|
|
PrivKey string
|
|
|
|
PubKey string
|
2017-11-01 23:41:39 +08:00
|
|
|
Comment string
|
2017-10-30 23:48:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type Host struct {
|
2017-10-31 23:22:40 +08:00
|
|
|
// FIXME: use uuid for ID
|
2017-10-30 23:48:14 +08:00
|
|
|
gorm.Model
|
2017-11-02 06:32:36 +08:00
|
|
|
Name string // FIXME: govalidator: min length 3, alphanum
|
2017-10-31 00:01:10 +08:00
|
|
|
Addr string
|
|
|
|
User string
|
|
|
|
Password string
|
2017-11-02 06:32:36 +08:00
|
|
|
SSHKey *SSHKey
|
2017-11-02 17:27:58 +08:00
|
|
|
SSHKeyID uint `gorm:"index"`
|
|
|
|
Fingerprint string // FIXME: replace with hostkey ?
|
2017-11-01 23:41:39 +08:00
|
|
|
Comment string
|
2017-10-31 23:22:40 +08:00
|
|
|
}
|
|
|
|
|
2017-11-03 08:46:55 +08:00
|
|
|
type UserKey struct {
|
|
|
|
gorm.Model
|
2017-11-04 06:31:46 +08:00
|
|
|
Key []byte
|
|
|
|
UserID uint
|
|
|
|
User *User
|
|
|
|
Comment string
|
2017-11-03 08:46:55 +08:00
|
|
|
}
|
|
|
|
|
2017-10-30 23:48:14 +08:00
|
|
|
type User struct {
|
2017-10-31 23:22:40 +08:00
|
|
|
// FIXME: use uuid for ID
|
2017-10-30 23:48:14 +08:00
|
|
|
gorm.Model
|
2017-11-03 08:46:55 +08:00
|
|
|
IsAdmin bool
|
2017-11-03 07:15:15 +08:00
|
|
|
Email string // FIXME: govalidator: email
|
2017-11-02 06:32:36 +08:00
|
|
|
Name string // FIXME: govalidator: min length 3, alphanum
|
2017-11-03 08:46:55 +08:00
|
|
|
Keys []UserKey
|
2017-11-01 23:41:39 +08:00
|
|
|
Comment string
|
2017-10-30 23:48:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func dbInit(db *gorm.DB) error {
|
|
|
|
db.AutoMigrate(&User{})
|
2017-10-31 16:24:18 +08:00
|
|
|
db.AutoMigrate(&SSHKey{})
|
2017-10-30 23:48:14 +08:00
|
|
|
db.AutoMigrate(&Host{})
|
2017-11-03 08:46:55 +08:00
|
|
|
db.AutoMigrate(&UserKey{})
|
2017-11-02 17:27:58 +08:00
|
|
|
db.Exec(`CREATE UNIQUE INDEX uix_keys_name ON "ssh_keys"("name") WHERE ("deleted_at" IS NULL)`)
|
|
|
|
db.Exec(`CREATE UNIQUE INDEX uix_hosts_name ON "hosts"("name") WHERE ("deleted_at" IS NULL)`)
|
2017-11-03 07:15:15 +08:00
|
|
|
db.Exec(`CREATE UNIQUE INDEX uix_users_name ON "users"("email") WHERE ("deleted_at" IS NULL)`)
|
2017-11-01 23:41:39 +08:00
|
|
|
|
|
|
|
// create default ssh key
|
|
|
|
var count uint
|
|
|
|
if err := db.Table("ssh_keys").Where("name = ?", "default").Count(&count).Error; err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if count == 0 {
|
|
|
|
key, err := NewSSHKey("rsa", 2048)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
key.Name = "default"
|
|
|
|
key.Comment = "created by sshportal"
|
2017-11-04 05:54:16 +08:00
|
|
|
if err := db.Create(&key).Error; err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// create host ssh key
|
|
|
|
if err := db.Table("ssh_keys").Where("name = ?", "host").Count(&count).Error; err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if count == 0 {
|
|
|
|
key, err := NewSSHKey("rsa", 2048)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
key.Name = "host"
|
|
|
|
key.Comment = "created by sshportal"
|
2017-11-01 23:41:39 +08:00
|
|
|
if err := db.Create(&key).Error; err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2017-10-30 23:48:14 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func dbDemo(db *gorm.DB) error {
|
2017-11-02 06:32:36 +08:00
|
|
|
key, err := FindKeyByIdOrName(db, "default")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:01:10 +08:00
|
|
|
var host1, host2, host3 Host
|
2017-11-02 06:32:36 +08:00
|
|
|
db.FirstOrCreate(&host1, &Host{Name: "sdf", Addr: "sdf.org:22", User: "new", SSHKeyID: key.ID})
|
|
|
|
db.FirstOrCreate(&host2, &Host{Name: "whoami", Addr: "whoami.filippo.io:22", User: "test", SSHKeyID: key.ID})
|
|
|
|
db.FirstOrCreate(&host3, &Host{Name: "ssh-chat", Addr: "chat.shazow.net:22", User: "test", SSHKeyID: key.ID, Fingerprint: "MD5:e5:d5:d1:75:90:38:42:f6:c7:03:d7:d0:56:7d:6a:db"})
|
2017-10-30 23:48:14 +08:00
|
|
|
return nil
|
|
|
|
}
|
2017-10-31 16:24:18 +08:00
|
|
|
|
|
|
|
func RemoteHostFromSession(s ssh.Session, db *gorm.DB) (*Host, error) {
|
|
|
|
var host Host
|
2017-11-02 06:42:17 +08:00
|
|
|
db.Preload("SSHKey").Where("name = ?", s.User()).Find(&host)
|
2017-10-31 16:24:18 +08:00
|
|
|
if host.Name == "" {
|
|
|
|
// FIXME: add available hosts
|
|
|
|
return nil, fmt.Errorf("No such target: %q", s.User())
|
|
|
|
}
|
|
|
|
return &host, nil
|
|
|
|
}
|
|
|
|
|
2017-10-31 23:22:40 +08:00
|
|
|
func (host *Host) URL() string {
|
|
|
|
return fmt.Sprintf("%s@%s", host.User, host.Addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewHostFromURL(rawurl string) (*Host, error) {
|
|
|
|
if !strings.Contains(rawurl, "://") {
|
|
|
|
rawurl = "ssh://" + rawurl
|
2017-10-31 16:24:18 +08:00
|
|
|
}
|
2017-10-31 23:22:40 +08:00
|
|
|
u, err := url.Parse(rawurl)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2017-10-31 16:24:18 +08:00
|
|
|
}
|
2017-10-31 23:22:40 +08:00
|
|
|
host := Host{Addr: u.Host}
|
2017-11-02 06:32:36 +08:00
|
|
|
if !strings.Contains(host.Addr, ":") {
|
|
|
|
host.Addr += ":22" // add port if not present
|
|
|
|
}
|
|
|
|
host.User = "root" // default username
|
2017-10-31 23:22:40 +08:00
|
|
|
if u.User != nil {
|
|
|
|
password, _ := u.User.Password()
|
|
|
|
host.Password = password
|
|
|
|
host.User = u.User.Username()
|
2017-10-31 16:24:18 +08:00
|
|
|
}
|
2017-10-31 23:22:40 +08:00
|
|
|
return &host, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (host *Host) Hostname() string {
|
|
|
|
return strings.Split(host.Addr, ":")[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
func FindHostByIdOrName(db *gorm.DB, query string) (*Host, error) {
|
|
|
|
var host Host
|
2017-11-02 06:32:36 +08:00
|
|
|
if err := db.Preload("SSHKey").Where("id = ?", query).Or("name = ?", query).First(&host).Error; err != nil {
|
2017-10-31 23:22:40 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &host, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func FindHostsByIdOrName(db *gorm.DB, queries []string) ([]*Host, error) {
|
|
|
|
var hosts []*Host
|
|
|
|
for _, query := range queries {
|
|
|
|
host, err := FindHostByIdOrName(db, query)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
hosts = append(hosts, host)
|
2017-10-31 16:24:18 +08:00
|
|
|
}
|
2017-10-31 23:22:40 +08:00
|
|
|
return hosts, nil
|
2017-10-31 16:24:18 +08:00
|
|
|
}
|
2017-11-01 22:48:30 +08:00
|
|
|
|
|
|
|
func FindKeyByIdOrName(db *gorm.DB, query string) (*SSHKey, error) {
|
|
|
|
var key SSHKey
|
|
|
|
if err := db.Where("id = ?", query).Or("name = ?", query).First(&key).Error; err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &key, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func FindKeysByIdOrName(db *gorm.DB, queries []string) ([]*SSHKey, error) {
|
|
|
|
var keys []*SSHKey
|
|
|
|
for _, query := range queries {
|
|
|
|
key, err := FindKeyByIdOrName(db, query)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
keys = append(keys, key)
|
|
|
|
}
|
|
|
|
return keys, nil
|
|
|
|
}
|
2017-11-03 07:15:15 +08:00
|
|
|
|
|
|
|
func FindUserByIdOrEmail(db *gorm.DB, query string) (*User, error) {
|
|
|
|
var user User
|
2017-11-03 08:46:55 +08:00
|
|
|
if err := db.Preload("Keys").Where("id = ?", query).Or("email = ?", query).First(&user).Error; err != nil {
|
2017-11-03 07:15:15 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &user, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func FindUsersByIdOrEmail(db *gorm.DB, queries []string) ([]*User, error) {
|
|
|
|
var users []*User
|
|
|
|
for _, query := range queries {
|
|
|
|
user, err := FindUserByIdOrEmail(db, query)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
users = append(users, user)
|
|
|
|
}
|
|
|
|
return users, nil
|
|
|
|
}
|
2017-11-04 06:31:46 +08:00
|
|
|
|
|
|
|
func FindUserkeyById(db *gorm.DB, query string) (*UserKey, error) {
|
|
|
|
var userkey UserKey
|
|
|
|
if err := db.Preload("User").Where("id = ?", query).First(&userkey).Error; err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &userkey, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func FindUserkeysById(db *gorm.DB, queries []string) ([]*UserKey, error) {
|
|
|
|
var userkeys []*UserKey
|
|
|
|
for _, query := range queries {
|
|
|
|
userkey, err := FindUserkeyById(db, query)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
userkeys = append(userkeys, userkey)
|
|
|
|
}
|
|
|
|
return userkeys, nil
|
|
|
|
}
|