Skip to content

Commit

Permalink
Added login/logout commands
Browse files Browse the repository at this point in the history
  • Loading branch information
pierotofy committed Jan 9, 2019
1 parent eca83fd commit fb9a8f9
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 23 deletions.
4 changes: 0 additions & 4 deletions cmd/odm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,5 @@ import (
)

func main() {
// fmt.Print("Enter password: ")
// bytePassword, _ := terminal.ReadPassword(int(syscall.Stdin))
// password := string(bytePassword)
// fmt.Printf("Your password is '%s'", password)
cmd.Execute()
}
40 changes: 40 additions & 0 deletions internal/cmd/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright © 2018 CloudODM Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
"github.com/OpenDroneMap/CloudODM/internal/config"
"github.com/OpenDroneMap/CloudODM/internal/logger"
"github.com/spf13/cobra"
)

var loginCmd = &cobra.Command{
Use: "login [--node default]",
Short: "Login with a node",
Run: func(cmd *cobra.Command, args []string) {
config.Initialize()

if config.CheckLogin(nodeName) != nil {
logger.Info("Logged in")
}
},
}

func init() {
loginCmd.Flags().StringVarP(&nodeName, "node", "n", "default", "Processing node to use")

rootCmd.AddCommand(loginCmd)
}
46 changes: 46 additions & 0 deletions internal/cmd/logout.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright © 2018 CloudODM Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
"github.com/OpenDroneMap/CloudODM/internal/config"
"github.com/OpenDroneMap/CloudODM/internal/logger"
"github.com/spf13/cobra"
)

var logoutCmd = &cobra.Command{
Use: "logout [--node default]",
Short: "Logout of a node",
Run: func(cmd *cobra.Command, args []string) {
config.Initialize()

node, err := config.User.GetNode(nodeName)
if err != nil {
logger.Error(err)
}

node.Token = ""
config.User.UpdateNode(nodeName, *node)

logger.Info("Logged out")
},
}

func init() {
logoutCmd.Flags().StringVarP(&nodeName, "node", "n", "default", "Processing node to use")

rootCmd.AddCommand(logoutCmd)
}
17 changes: 3 additions & 14 deletions internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"github.com/OpenDroneMap/CloudODM/internal/config"
"github.com/OpenDroneMap/CloudODM/internal/fs"
"github.com/OpenDroneMap/CloudODM/internal/logger"
"github.com/OpenDroneMap/CloudODM/internal/odm"

"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -55,19 +54,7 @@ var rootCmd = &cobra.Command{

logger.Debug("Options: " + strings.Join(options, " "))

node, err := config.User.GetNode(nodeName)
if err != nil {
logger.Error(err)
}

info, err := node.Info()
err = node.CheckAuthorization(err)
if err != nil {
if err == odm.ErrAuthRequired {
logger.Debug("AUTH")
}
logger.Error(err)
}
info := config.CheckLogin(nodeName)

// Check max images
if len(inputFiles) > info.MaxImages {
Expand All @@ -93,6 +80,8 @@ func Execute() {
func init() {
rootCmd.PersistentFlags().BoolVarP(&logger.VerboseFlag, "verbose", "v", false, "show verbose output")
rootCmd.PersistentFlags().BoolVarP(&logger.DebugFlag, "debug", "d", false, "show debug output")
rootCmd.PersistentFlags().BoolVarP(&logger.QuietFlag, "quiet", "q", false, "suppress output")

rootCmd.Flags().StringVarP(&outputPath, "output", "o", "./output", "directory where to store processing results")
rootCmd.Flags().StringVarP(&nodeName, "node", "n", "default", "Processing node to use")
rootCmd.Flags().SetInterspersed(false)
Expand Down
42 changes: 42 additions & 0 deletions internal/config/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package config

import (
"github.com/OpenDroneMap/CloudODM/internal/logger"
"github.com/OpenDroneMap/CloudODM/internal/odm"
)

// CheckLogin checks if the node needs login
// if it does, it attempts to login
// it it doesn't, returns node.Info()
// on error, it prints a message and exits
func CheckLogin(nodeName string) *odm.InfoResponse {
node, err := User.GetNode(nodeName)
if err != nil {
logger.Error(err)
}

info, err := node.Info()
err = node.CheckAuthentication(err)
if err != nil {
if err == odm.ErrAuthRequired {
token, err := node.TryLogin()
if err != nil {
logger.Error(err)
}

// Validate token
node.Token = token
info, err = node.Info()
err = node.CheckAuthentication(err)
if err != nil {
logger.Error(err)
}

User.UpdateNode(nodeName, *node)
} else {
logger.Error(err)
}
}

return info
}
7 changes: 6 additions & 1 deletion internal/config/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func saveToFile(conf Configuration, filePath string) {

jsonFile.Write(jsonData)

logger.Debug("Wrote default configuration in " + filePath)
logger.Debug("Wrote configuration to " + filePath)
}

func loadFromFile(filePath string) Configuration {
Expand Down Expand Up @@ -155,3 +155,8 @@ func (c Configuration) GetNode(name string) (*odm.Node, error) {

return &node, nil
}

func (c Configuration) UpdateNode(name string, node odm.Node) {
c.Nodes[name] = node
c.Save()
}
11 changes: 9 additions & 2 deletions internal/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ var VerboseFlag bool
// DebugFlag sets debug output
var DebugFlag bool

// QuietFlag supresses all output
var QuietFlag bool

// Debug message (if DebugFlag is enabled)
func Debug(a ...interface{}) {
if DebugFlag {
Expand All @@ -27,11 +30,15 @@ func Verbose(a ...interface{}) {

// Info message
func Info(a ...interface{}) {
fmt.Println(a...)
if !QuietFlag {
fmt.Println(a...)
}
}

//Error message and exit
func Error(a ...interface{}) {
fmt.Println(a...)
if !QuietFlag {
fmt.Println(a...)
}
os.Exit(1)
}
111 changes: 109 additions & 2 deletions internal/odm/node.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package odm

import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"syscall"

"golang.org/x/crypto/ssh/terminal"

"github.com/OpenDroneMap/CloudODM/internal/logger"
)
Expand All @@ -26,6 +33,12 @@ type InfoResponse struct {
Error string `json:"error"`
}

type AuthInfoResponse struct {
Message string `json:"message"`
LoginUrl string `json:"loginUrl"`
RegisterUrl string `json:"registerUrl"`
}

// Node is a NodeODM processing node
type Node struct {
URL string `json:"url"`
Expand Down Expand Up @@ -74,7 +87,29 @@ func (n Node) apiGET(path string) ([]byte, error) {

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
logger.Info(err)
return nil, err
}

return body, nil
}

func (n Node) apiPOST(path string, values map[string]string) ([]byte, error) {
url := n.URLFor(path)
logger.Debug("POST: " + url)

formData, _ := json.Marshal(values)
resp, err := http.Post(url, "application/json", bytes.NewBuffer(formData))
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode != 200 {
return nil, errors.New("Server returned status code: " + strconv.Itoa(resp.StatusCode))
}

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}

Expand Down Expand Up @@ -106,7 +141,7 @@ func (n Node) Info() (*InfoResponse, error) {
return &res, nil
}

func (n Node) CheckAuthorization(err error) error {
func (n Node) CheckAuthentication(err error) error {
if err != nil {
if err == ErrUnauthorized {
// Is there a token?
Expand All @@ -122,3 +157,75 @@ func (n Node) CheckAuthorization(err error) error {

return nil
}

type LoginResponse struct {
Token string `json:"token"`
}

func (n Node) TryLogin() (token string, err error) {
res := AuthInfoResponse{}
body, err := n.apiGET("/auth/info")
if err != nil {
return "", err
}
if err := json.Unmarshal(body, &res); err != nil {
return "", err
}

if res.Message != "" {
logger.Info("")
logger.Info(res.Message)
logger.Info("")
}

if res.LoginUrl != "" {
reader := bufio.NewReader(os.Stdin)
username := ""
for len(username) == 0 {
fmt.Print("Enter username: ")
username, _ = reader.ReadString('\n')
username = strings.TrimSpace(username)
}

password := ""
for len(password) == 0 {
fmt.Print("Enter password: ")
bytePassword, _ := terminal.ReadPassword(int(syscall.Stdin))
password = string(bytePassword)
}

logger.Debug("")
logger.Debug("POST: " + res.LoginUrl)

formData, _ := json.Marshal(map[string]string{"username": username, "password": password})
resp, err := http.Post(res.LoginUrl, "application/json", bytes.NewBuffer(formData))
if err != nil {
return "", err
}
defer resp.Body.Close()

if resp.StatusCode != 200 {
return "", errors.New("Login URL returned status code: " + strconv.Itoa(resp.StatusCode))
}

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}

res := LoginResponse{}
if err := json.Unmarshal(body, &res); err != nil {
return "", err
}

if res.Token == "" {
return "", errors.New("Login failed")
}

return res.Token, nil
}

// TODO: support for res.RegisterUrl

return "", errors.New("Cannot login")
}

0 comments on commit fb9a8f9

Please sign in to comment.