2018-10-08 19:20:28 +00:00
package tunnel
import (
"fmt"
2020-11-09 03:25:35 +00:00
"io/ioutil"
2018-10-08 19:20:28 +00:00
"net/url"
"os"
"path/filepath"
"syscall"
2021-03-23 14:30:43 +00:00
homedir "github.com/mitchellh/go-homedir"
2020-04-29 20:51:32 +00:00
"github.com/pkg/errors"
2020-11-25 06:55:13 +00:00
"github.com/urfave/cli/v2"
2020-10-09 17:07:08 +00:00
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
2021-03-08 16:46:23 +00:00
"github.com/cloudflare/cloudflared/config"
2023-04-12 16:43:38 +00:00
"github.com/cloudflare/cloudflared/credentials"
2020-10-09 17:07:08 +00:00
"github.com/cloudflare/cloudflared/logger"
2021-03-08 16:46:23 +00:00
"github.com/cloudflare/cloudflared/token"
2018-10-08 19:20:28 +00:00
)
const (
baseLoginURL = "https://dash.cloudflare.com/argotunnel"
2021-04-30 16:38:07 +00:00
callbackStoreURL = "https://login.cloudflareaccess.org/"
2018-10-08 19:20:28 +00:00
)
2020-10-09 17:07:08 +00:00
func buildLoginSubcommand ( hidden bool ) * cli . Command {
return & cli . Command {
Name : "login" ,
2021-03-16 22:36:46 +00:00
Action : cliutil . ConfiguredAction ( login ) ,
2020-10-09 17:07:08 +00:00
Usage : "Generate a configuration file with your login details" ,
ArgsUsage : " " ,
2021-03-16 22:36:46 +00:00
Hidden : hidden ,
2020-10-09 17:07:08 +00:00
}
}
2018-10-08 19:20:28 +00:00
func login ( c * cli . Context ) error {
2020-11-25 06:55:13 +00:00
log := logger . CreateLoggerFromContext ( c , logger . EnableTerminalLog )
2020-04-29 20:51:32 +00:00
2018-10-08 19:20:28 +00:00
path , ok , err := checkForExistingCert ( )
if ok {
fmt . Fprintf ( os . Stdout , "You have an existing certificate at %s which login would overwrite.\nIf this is intentional, please move or delete that file then run this command again.\n" , path )
return nil
} else if err != nil {
return err
}
loginURL , err := url . Parse ( baseLoginURL )
if err != nil {
// shouldn't happen, URL is hardcoded
return err
}
2021-03-08 16:46:23 +00:00
resourceData , err := token . RunTransfer (
2020-11-25 06:55:13 +00:00
loginURL ,
"cert" ,
"callback" ,
callbackStoreURL ,
false ,
false ,
log ,
)
2018-10-08 19:20:28 +00:00
if err != nil {
fmt . Fprintf ( os . Stderr , "Failed to write the certificate due to the following error:\n%v\n\nYour browser will download the certificate instead. You will have to manually\ncopy it to the following path:\n\n%s\n" , err , path )
return err
}
2020-11-09 03:25:35 +00:00
if err := ioutil . WriteFile ( path , resourceData , 0600 ) ; err != nil {
return errors . Wrap ( err , fmt . Sprintf ( "error writing cert to %s" , path ) )
}
2018-10-08 19:20:28 +00:00
fmt . Fprintf ( os . Stdout , "You have successfully logged in.\nIf you wish to copy your credentials to a server, they have been saved to:\n%s\n" , path )
return nil
}
func checkForExistingCert ( ) ( string , bool , error ) {
2020-08-14 20:52:47 +00:00
configPath , err := homedir . Expand ( config . DefaultConfigSearchDirectories ( ) [ 0 ] )
2018-10-08 19:20:28 +00:00
if err != nil {
return "" , false , err
}
ok , err := config . FileExists ( configPath )
if ! ok && err == nil {
// create config directory if doesn't already exist
err = os . Mkdir ( configPath , 0700 )
}
if err != nil {
return "" , false , err
}
2023-04-12 16:43:38 +00:00
path := filepath . Join ( configPath , credentials . DefaultCredentialFile )
2018-10-08 19:20:28 +00:00
fileInfo , err := os . Stat ( path )
if err == nil && fileInfo . Size ( ) > 0 {
return path , true , nil
}
if err != nil && err . ( * os . PathError ) . Err != syscall . ENOENT {
return path , false , err
}
return path , false , nil
}