Skip to content

Commit

Permalink
initial implementation (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
Eric Schrock authored and Derek Smart committed Jan 4, 2020
1 parent ee55657 commit 74c8fa6
Show file tree
Hide file tree
Showing 8 changed files with 466 additions and 9 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# Build and test on pull request
#
name: Pull Request

on:
pull_request:
types: [opened, synchronize, reopened]

jobs:
build:
name: Build and Test
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v1
- uses: actions/setup-go@v1
with:
go-version: '1.13.5'
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# OS Generated files
.DS_Store

# Temporary files
.*.swp
*.swp

# IDE files
/.idea
10 changes: 5 additions & 5 deletions DEVELOPING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ For general information about contributing changes, see the

## How it Works

Describe the internal mechanisms necessary for developers to understand how
to get started making changes.
The provider uses the Titan `remote-sdk-go` to provide interfaces for
Titan to use.

## Building

Describe how to build the project.
Run `go build -v ./...`.

## Testing

Describe how to test the project.
Run `go test -v ./...`.

## Releasing

Describe how to generate new releases.
Push a tag of the form `v<X>.<Y>.<Z>`, and publish the draft release in GitHub.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# About this Project
# Titan SSH Provider

Describe the project for users.
This is a basic Titan SSH provider. For more information on how it works,
consult the titan documentation.

## Contributing

Expand Down
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module github.com/titan-data/s3web-remote-go

require (
github.com/stretchr/testify v1.4.0
github.com/titan-data/remote-sdk-go v0.0.3
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876
)

go 1.13
22 changes: 22 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/titan-data/remote-sdk-go v0.0.2 h1:NEta4CwcUPj7PGbbxvpxIXem7t0EIbXBKegJsy1hafE=
github.com/titan-data/remote-sdk-go v0.0.2/go.mod h1:b4McaOFiLYWv2/wCQW/sE2BcCSNz/Ae6iKKEtqw703w=
github.com/titan-data/remote-sdk-go v0.0.3 h1:kGLc7JP7znTcXyl3gRML2jEST99ebdhz0Cn+nVdL6SQ=
github.com/titan-data/remote-sdk-go v0.0.3/go.mod h1:b4McaOFiLYWv2/wCQW/sE2BcCSNz/Ae6iKKEtqw703w=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
139 changes: 139 additions & 0 deletions ssh/ssh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright The Titan Project Contributors.
*/
package ssh

import (
"errors"
"fmt"
"github.com/titan-data/remote-sdk-go/remote"
"golang.org/x/crypto/ssh/terminal"
"io/ioutil"
"net/url"
"strconv"
"strings"
)

type sshRemote struct {
}

func (s sshRemote) Type() string {
return "ssh"
}

func (s sshRemote) FromURL(url *url.URL, additionalProperties map[string]string) (map[string]interface{}, error) {
if url.Scheme != "ssh" {
return nil, errors.New("invalid remote scheme")
}

if url.Path == "" {
return nil, errors.New("missing remote path")
}

if url.Hostname() == "" {
return nil, errors.New("missing remote host")
}

if url.User == nil || url.User.Username() == "" {
return nil, errors.New("missing remote username")
}

path := url.Path
if strings.Index(path, "/~/") == 0 {
path = path[3:]
}

keyFile := additionalProperties["keyFile"]
password, passwordSet := url.User.Password()
if keyFile != "" && passwordSet {
return nil, errors.New("both remote password and key file cannot be specified")
}

for k := range additionalProperties {
if k != "keyFile" {
return nil, errors.New(fmt.Sprintf("invalid rmeote property '%s'", k))
}
}

result := map[string]interface{}{
"username": url.User.Username(),
"address": url.Hostname(),
"path": path,
}

if password != "" {
result["password"] = password
}
if url.Port() != "" {
port, err := strconv.Atoi(url.Port())
if err != nil {
return nil, fmt.Errorf("invalid port '%s': %w", url.Port(), err)
}
result["port"] = port
}
if keyFile != "" {
result["keyFile"] = keyFile
}

return result, nil
}

func (s sshRemote) ToURL(properties map[string]interface{}) (string, map[string]string, error) {
u := fmt.Sprintf("ssh://%s", properties["username"])
if properties["password"] != nil {
u += ":*****"
}
u += fmt.Sprintf("@%s", properties["address"])
if properties["port"] != nil {
var port = 0
if flt, ok := properties["port"].(float32); ok {
port = int(flt)
} else if flt, ok := properties["port"].(float64); ok {
port = int(flt)
} else {
port = properties["port"].(int)
}
u += fmt.Sprintf(":%d", port)
}
if properties["path"].(string)[0:1] != "/" {
u += "/~/"
}
u += properties["path"].(string)

retProps := map[string]string{}
if properties["keyFile"] != nil {
retProps["keyFile"] = properties["keyFile"].(string)
}

return u, retProps, nil
}

var readPassword = terminal.ReadPassword
var fmtPrintf = fmt.Printf

func (s sshRemote) GetParameters(remoteProperties map[string]interface{}) (map[string]interface{}, error) {
result := map[string]interface{}{}

if remoteProperties["keyFile"] != nil {
content, err := ioutil.ReadFile(remoteProperties["keyFile"].(string))
if err != nil {
return nil, fmt.Errorf("failed to read key file %s: %w", remoteProperties["keyFile"], err)
}
result["key"] = string(content)
}

if remoteProperties["password"] == nil && remoteProperties["keyFile"] == nil {
fmtPrintf("password: ")
pw, err := readPassword(0)
if err != nil {
return nil, fmt.Errorf("failed to read password: %w", err)
}
result["password"] = string(pw)
}

return result, nil
}

func init() {
remote.Register(sshRemote{})
}
Loading

0 comments on commit 74c8fa6

Please sign in to comment.