mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 17:27:40 +00:00
feat: cli login via browser
This commit is contained in:
+4
-2
@@ -5,6 +5,7 @@ go 1.19
|
|||||||
require (
|
require (
|
||||||
github.com/99designs/keyring v1.2.2
|
github.com/99designs/keyring v1.2.2
|
||||||
github.com/charmbracelet/lipgloss v0.5.0
|
github.com/charmbracelet/lipgloss v0.5.0
|
||||||
|
github.com/denisbrodbeck/machineid v1.0.1
|
||||||
github.com/fatih/semgroup v1.2.0
|
github.com/fatih/semgroup v1.2.0
|
||||||
github.com/gitleaks/go-gitdiff v0.8.0
|
github.com/gitleaks/go-gitdiff v0.8.0
|
||||||
github.com/h2non/filetype v1.1.3
|
github.com/h2non/filetype v1.1.3
|
||||||
@@ -14,6 +15,7 @@ require (
|
|||||||
github.com/muesli/reflow v0.3.0
|
github.com/muesli/reflow v0.3.0
|
||||||
github.com/muesli/roff v0.1.0
|
github.com/muesli/roff v0.1.0
|
||||||
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9
|
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9
|
||||||
|
github.com/posthog/posthog-go v0.0.0-20221221115252-24dfed35d71a
|
||||||
github.com/rs/zerolog v1.26.1
|
github.com/rs/zerolog v1.26.1
|
||||||
github.com/spf13/cobra v1.6.1
|
github.com/spf13/cobra v1.6.1
|
||||||
github.com/spf13/viper v1.8.1
|
github.com/spf13/viper v1.8.1
|
||||||
@@ -28,7 +30,6 @@ require (
|
|||||||
github.com/chzyer/readline v1.5.1 // indirect
|
github.com/chzyer/readline v1.5.1 // indirect
|
||||||
github.com/danieljoos/wincred v1.1.2 // indirect
|
github.com/danieljoos/wincred v1.1.2 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/denisbrodbeck/machineid v1.0.1 // indirect
|
|
||||||
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
|
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
github.com/go-openapi/errors v0.20.2 // indirect
|
github.com/go-openapi/errors v0.20.2 // indirect
|
||||||
@@ -47,9 +48,10 @@ require (
|
|||||||
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 // indirect
|
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 // indirect
|
||||||
github.com/oklog/ulid v1.3.1 // indirect
|
github.com/oklog/ulid v1.3.1 // indirect
|
||||||
github.com/pelletier/go-toml v1.9.3 // indirect
|
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/posthog/posthog-go v0.0.0-20221221115252-24dfed35d71a // indirect
|
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
|
github.com/rs/cors v1.9.0 // indirect
|
||||||
github.com/spf13/afero v1.6.0 // indirect
|
github.com/spf13/afero v1.6.0 // indirect
|
||||||
github.com/spf13/cast v1.3.1 // indirect
|
github.com/spf13/cast v1.3.1 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
|
|||||||
@@ -283,6 +283,8 @@ github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5d
|
|||||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 h1:lL+y4Xv20pVlCGyLzNHRC0I0rIHhIL1lTvHizoS/dU8=
|
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 h1:lL+y4Xv20pVlCGyLzNHRC0I0rIHhIL1lTvHizoS/dU8=
|
||||||
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw=
|
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw=
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||||
@@ -297,6 +299,8 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
|||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
|
||||||
|
github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
|
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
|
||||||
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
|
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
|
||||||
@@ -520,6 +524,7 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|||||||
+130
-6
@@ -6,10 +6,14 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
@@ -22,7 +26,9 @@ import (
|
|||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
"github.com/manifoldco/promptui"
|
"github.com/manifoldco/promptui"
|
||||||
|
"github.com/pkg/browser"
|
||||||
"github.com/posthog/posthog-go"
|
"github.com/posthog/posthog-go"
|
||||||
|
"github.com/rs/cors"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/crypto/argon2"
|
"golang.org/x/crypto/argon2"
|
||||||
@@ -90,17 +96,44 @@ var loginCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
email, password, err := askForLoginCredentials()
|
var (
|
||||||
|
email string
|
||||||
|
password string
|
||||||
|
loginOneResponse *api.GetLoginOneV2Response
|
||||||
|
loginTwoResponse *api.GetLoginTwoV2Response
|
||||||
|
)
|
||||||
|
|
||||||
|
//check for --browser flag
|
||||||
|
browserLogin, err := cmd.Flags().GetBool("browser")
|
||||||
|
if err != nil {
|
||||||
|
util.HandleError(err, "Unable to parse browser flag")
|
||||||
|
}
|
||||||
|
|
||||||
|
if browserLogin {
|
||||||
|
log.Debug().Msg("Login via browser")
|
||||||
|
//call browser login function
|
||||||
|
loginResponse, err := browserCliLogin()
|
||||||
|
if err != nil {
|
||||||
|
util.HandleError(err, err.Error())
|
||||||
|
}
|
||||||
|
email = loginResponse.Email
|
||||||
|
password = loginResponse.Password
|
||||||
|
loginOneResponse = &loginResponse.LoginOneResponse
|
||||||
|
loginTwoResponse = &loginResponse.LoginTwoResponse
|
||||||
|
//util.HandleError(errors.New("not implemented"), " login via browser not fully implemented")
|
||||||
|
} else {
|
||||||
|
email, password, err = askForLoginCredentials()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.HandleError(err, "Unable to parse email and password for authentication")
|
util.HandleError(err, "Unable to parse email and password for authentication")
|
||||||
}
|
}
|
||||||
|
|
||||||
loginOneResponse, loginTwoResponse, err := getFreshUserCredentials(email, password)
|
loginOneResponse, loginTwoResponse, err = getFreshUserCredentials(email, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Unable to authenticate with the provided credentials, please try again")
|
fmt.Println("Unable to authenticate with the provided credentials, please try again")
|
||||||
log.Debug().Err(err)
|
log.Debug().Err(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if loginTwoResponse.MfaEnabled {
|
if loginTwoResponse.MfaEnabled {
|
||||||
i := 1
|
i := 1
|
||||||
@@ -282,6 +315,7 @@ var loginCmd = &cobra.Command{
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(loginCmd)
|
rootCmd.AddCommand(loginCmd)
|
||||||
|
loginCmd.Flags().BoolP("browser", "b", false, "Login via browser")
|
||||||
}
|
}
|
||||||
|
|
||||||
func DomainOverridePrompt() (bool, error) {
|
func DomainOverridePrompt() (bool, error) {
|
||||||
@@ -326,7 +360,8 @@ func askForDomain() error {
|
|||||||
|
|
||||||
if selectedHostingOption == INFISICAL_CLOUD {
|
if selectedHostingOption == INFISICAL_CLOUD {
|
||||||
//cloud option
|
//cloud option
|
||||||
config.INFISICAL_URL = util.INFISICAL_DEFAULT_API_URL
|
config.INFISICAL_URL = fmt.Sprintf("%s/api", util.INFISICAL_DEFAULT_URL)
|
||||||
|
config.INFISICAL_LOGIN_URL = fmt.Sprintf("%s/login", util.INFISICAL_DEFAULT_URL)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +376,7 @@ func askForDomain() error {
|
|||||||
domainPrompt := promptui.Prompt{
|
domainPrompt := promptui.Prompt{
|
||||||
Label: "Domain",
|
Label: "Domain",
|
||||||
Validate: urlValidation,
|
Validate: urlValidation,
|
||||||
Default: "Example - https://my-self-hosted-instance.com/api",
|
Default: "Example - https://my-self-hosted-instance.com",
|
||||||
}
|
}
|
||||||
|
|
||||||
domain, err := domainPrompt.Run()
|
domain, err := domainPrompt.Run()
|
||||||
@@ -349,8 +384,9 @@ func askForDomain() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
//set api url
|
//set api and login url
|
||||||
config.INFISICAL_URL = domain
|
config.INFISICAL_URL = fmt.Sprintf("%s/api", domain)
|
||||||
|
config.INFISICAL_LOGIN_URL = fmt.Sprintf("%s/login", domain)
|
||||||
//return nil
|
//return nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -476,3 +512,91 @@ func askForMFACode() string {
|
|||||||
|
|
||||||
return mfaVerifyCode
|
return mfaVerifyCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CliLoginResponse struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
LoginOneResponse api.GetLoginOneV2Response `json:"loginOneResponse"`
|
||||||
|
LoginTwoResponse api.GetLoginTwoV2Response `json:"loginTwoResponse"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manages the browser login flow
|
||||||
|
// returns a CLILoginResponse on success and an error on failure
|
||||||
|
func browserCliLogin() (CliLoginResponse, error) {
|
||||||
|
|
||||||
|
//create listener
|
||||||
|
listener, err := net.Listen("tcp", ":0")
|
||||||
|
if err != nil {
|
||||||
|
return CliLoginResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//get callback port
|
||||||
|
callbackPort := listener.Addr().(*net.TCPAddr).Port
|
||||||
|
url := fmt.Sprintf("%s?callback_port=%d", config.INFISICAL_LOGIN_URL, callbackPort)
|
||||||
|
|
||||||
|
//open browser and login
|
||||||
|
err = browser.OpenURL(url)
|
||||||
|
if err != nil {
|
||||||
|
return CliLoginResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//flow channels
|
||||||
|
success := make(chan CliLoginResponse)
|
||||||
|
failure := make(chan error)
|
||||||
|
timeout := time.After(time.Second * 60)
|
||||||
|
|
||||||
|
//create handler
|
||||||
|
c := cors.New(cors.Options{
|
||||||
|
AllowedOrigins: []string{strings.ReplaceAll(config.INFISICAL_LOGIN_URL, "/login", "")},
|
||||||
|
AllowCredentials: true,
|
||||||
|
AllowedMethods: []string{"POST", "OPTIONS"},
|
||||||
|
AllowedHeaders: []string{"Content-Type"},
|
||||||
|
Debug: false,
|
||||||
|
})
|
||||||
|
corsHandler := c.Handler(browserLoginHandler(success, failure))
|
||||||
|
|
||||||
|
log.Debug().Msgf("Callback server listening on port %d", callbackPort)
|
||||||
|
go http.Serve(listener, corsHandler)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case loginResponse := <-success:
|
||||||
|
err = closeListener(&listener)
|
||||||
|
return loginResponse, nil
|
||||||
|
|
||||||
|
case err = <-failure:
|
||||||
|
err = closeListener(&listener)
|
||||||
|
return CliLoginResponse{}, err
|
||||||
|
|
||||||
|
case _ = <-timeout:
|
||||||
|
err = closeListener(&listener)
|
||||||
|
return CliLoginResponse{}, errors.New("server timeout")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeListener(listener *net.Listener) error {
|
||||||
|
err := (*listener).Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debug().Msg("Callback server shutdown successfully")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func browserLoginHandler(success chan CliLoginResponse, failure chan error) http.HandlerFunc {
|
||||||
|
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var loginResponse CliLoginResponse
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(r.Body)
|
||||||
|
err := decoder.Decode(&loginResponse)
|
||||||
|
if err != nil {
|
||||||
|
failure <- err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
success <- loginResponse
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ package config
|
|||||||
|
|
||||||
var INFISICAL_URL string
|
var INFISICAL_URL string
|
||||||
var INFISICAL_URL_MANUAL_OVERRIDE string
|
var INFISICAL_URL_MANUAL_OVERRIDE string
|
||||||
|
var INFISICAL_LOGIN_URL string
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const (
|
|||||||
CONFIG_FILE_NAME = "infisical-config.json"
|
CONFIG_FILE_NAME = "infisical-config.json"
|
||||||
CONFIG_FOLDER_NAME = ".infisical"
|
CONFIG_FOLDER_NAME = ".infisical"
|
||||||
INFISICAL_DEFAULT_API_URL = "https://app.infisical.com/api"
|
INFISICAL_DEFAULT_API_URL = "https://app.infisical.com/api"
|
||||||
|
INFISICAL_DEFAULT_URL = "https://app.infisical.com"
|
||||||
INFISICAL_WORKSPACE_CONFIG_FILE_NAME = ".infisical.json"
|
INFISICAL_WORKSPACE_CONFIG_FILE_NAME = ".infisical.json"
|
||||||
INFISICAL_TOKEN_NAME = "INFISICAL_TOKEN"
|
INFISICAL_TOKEN_NAME = "INFISICAL_TOKEN"
|
||||||
SECRET_TYPE_PERSONAL = "personal"
|
SECRET_TYPE_PERSONAL = "personal"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const ContentSecurityPolicy = `
|
|||||||
style-src 'self' https://rsms.me 'unsafe-inline';
|
style-src 'self' https://rsms.me 'unsafe-inline';
|
||||||
child-src https://api.stripe.com;
|
child-src https://api.stripe.com;
|
||||||
frame-src https://js.stripe.com/ https://api.stripe.com;
|
frame-src https://js.stripe.com/ https://api.stripe.com;
|
||||||
connect-src 'self' https://api.heroku.com/ https://id.heroku.com/oauth/authorize https://id.heroku.com/oauth/token https://checkout.stripe.com https://app.posthog.com https://api.stripe.com;
|
connect-src 'self' https://api.heroku.com/ https://id.heroku.com/oauth/authorize https://id.heroku.com/oauth/token https://checkout.stripe.com https://app.posthog.com https://api.stripe.com http://localhost:*;
|
||||||
img-src 'self' https://*.stripe.com https://i.ytimg.com/ data:;
|
img-src 'self' https://*.stripe.com https://i.ytimg.com/ data:;
|
||||||
media-src;
|
media-src;
|
||||||
font-src 'self' https://maxcdn.bootstrapcdn.com https://rsms.me https://fonts.gstatic.com;
|
font-src 'self' https://maxcdn.bootstrapcdn.com https://rsms.me https://fonts.gstatic.com;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useState } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
import axios from "axios"
|
||||||
|
|
||||||
import attemptLogin from '@app/components/utilities/attemptLogin';
|
import attemptLogin from '@app/components/utilities/attemptLogin';
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ import Error from '../basic/Error';
|
|||||||
// import { faGoogle } from '@fortawesome/free-brands-svg-icons';
|
// import { faGoogle } from '@fortawesome/free-brands-svg-icons';
|
||||||
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { Button, Input } from '../v2';
|
import { Button, Input } from '../v2';
|
||||||
|
import attemptCliLogin from '../utilities/attemptCliLogin';
|
||||||
|
|
||||||
export default function InitialLoginStep({
|
export default function InitialLoginStep({
|
||||||
setStep,
|
setStep,
|
||||||
@@ -36,6 +38,31 @@ export default function InitialLoginStep({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
const queryParams = new URLSearchParams(location.search)
|
||||||
|
if (queryParams) {
|
||||||
|
const callbackPort = queryParams.get("callback_port")
|
||||||
|
|
||||||
|
//attemptCliLogin
|
||||||
|
const isCliLoginSuccessful = await attemptCliLogin({
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isCliLoginSuccessful && isCliLoginSuccessful.success) {
|
||||||
|
// case: login was successful
|
||||||
|
const cliUrl = `http://localhost:${callbackPort}`
|
||||||
|
|
||||||
|
//send request to server endpoint
|
||||||
|
const instance = axios.create()
|
||||||
|
const cliResp = await instance.post(cliUrl,{...isCliLoginSuccessful.loginResponse,email,password})
|
||||||
|
|
||||||
|
//cli page
|
||||||
|
router.push("/cli-redirect");
|
||||||
|
|
||||||
|
//on success, router.push to cli Login Successful page
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const isLoginSuccessful = await attemptLogin({
|
const isLoginSuccessful = await attemptLogin({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
@@ -53,6 +80,8 @@ export default function InitialLoginStep({
|
|||||||
// case: login does not require MFA step
|
// case: login does not require MFA step
|
||||||
router.push(`/dashboard/${localStorage.getItem('projectData.id')}`);
|
router.push(`/dashboard/${localStorage.getItem('projectData.id')}`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setLoginError(true);
|
setLoginError(true);
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
/* eslint-disable prefer-destructuring */
|
||||||
|
import jsrp from 'jsrp';
|
||||||
|
|
||||||
|
import login1 from '@app/pages/api/auth/Login1';
|
||||||
|
import login2 from '@app/pages/api/auth/Login2';
|
||||||
|
import getOrganizations from '@app/pages/api/organization/getOrgs';
|
||||||
|
import getOrganizationUserProjects from '@app/pages/api/organization/GetOrgUserProjects';
|
||||||
|
import KeyService from '@app/services/KeyService';
|
||||||
|
|
||||||
|
import Telemetry from './telemetry/Telemetry';
|
||||||
|
import { saveTokenToLocalStorage } from './saveTokenToLocalStorage';
|
||||||
|
import SecurityClient from './SecurityClient';
|
||||||
|
|
||||||
|
// eslint-disable-next-line new-cap
|
||||||
|
const client = new jsrp.client();
|
||||||
|
|
||||||
|
interface IsCliLoginSuccessful {
|
||||||
|
loginResponse: {
|
||||||
|
loginOneResponse: {
|
||||||
|
serverPublicKey: string;
|
||||||
|
salt: string;
|
||||||
|
};
|
||||||
|
loginTwoResponse: {
|
||||||
|
mfaEnabled: boolean;
|
||||||
|
token: string;
|
||||||
|
encryptionVersion?: number;
|
||||||
|
protectedKey?: string;
|
||||||
|
protectedKeyIV?: string;
|
||||||
|
protectedKeyTag?: string;
|
||||||
|
publicKey?: string;
|
||||||
|
encryptedPrivateKey?: string;
|
||||||
|
iv?: string;
|
||||||
|
tag?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether or not login is successful for user with email [email]
|
||||||
|
* and password [password]
|
||||||
|
* @param {string} email - email of user to log in
|
||||||
|
* @param {string} password - password of user to log in
|
||||||
|
*/
|
||||||
|
const attemptLogin = async (
|
||||||
|
{
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
providerAuthToken,
|
||||||
|
}: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
providerAuthToken?: string;
|
||||||
|
}
|
||||||
|
): Promise<IsCliLoginSuccessful> => {
|
||||||
|
|
||||||
|
const telemetry = new Telemetry().getInstance();
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
client.init(
|
||||||
|
{
|
||||||
|
username: email,
|
||||||
|
password
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
try {
|
||||||
|
const clientPublicKey = client.getPublicKey();
|
||||||
|
const { serverPublicKey, salt } = await login1({
|
||||||
|
email,
|
||||||
|
clientPublicKey,
|
||||||
|
providerAuthToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
client.setSalt(salt);
|
||||||
|
client.setServerPublicKey(serverPublicKey);
|
||||||
|
const clientProof = client.getProof(); // called M1
|
||||||
|
|
||||||
|
const {
|
||||||
|
mfaEnabled,
|
||||||
|
encryptionVersion,
|
||||||
|
protectedKey,
|
||||||
|
protectedKeyIV,
|
||||||
|
protectedKeyTag,
|
||||||
|
token,
|
||||||
|
publicKey,
|
||||||
|
encryptedPrivateKey,
|
||||||
|
iv,
|
||||||
|
tag
|
||||||
|
} = await login2(
|
||||||
|
{
|
||||||
|
email,
|
||||||
|
clientProof,
|
||||||
|
providerAuthToken,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
loginResponse: {
|
||||||
|
loginOneResponse: { serverPublicKey, salt },
|
||||||
|
loginTwoResponse: {
|
||||||
|
mfaEnabled,
|
||||||
|
encryptionVersion,
|
||||||
|
protectedKey,
|
||||||
|
protectedKeyIV,
|
||||||
|
protectedKeyTag,
|
||||||
|
token,
|
||||||
|
publicKey,
|
||||||
|
encryptedPrivateKey,
|
||||||
|
iv,
|
||||||
|
tag
|
||||||
|
}
|
||||||
|
},
|
||||||
|
success: true
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default attemptLogin;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import Head from 'next/head';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function CliRedirect() {
|
||||||
|
return (
|
||||||
|
<div className='bg-bunker-800 md:h-screen flex flex-col justify-between'>
|
||||||
|
<Head>
|
||||||
|
<title>Infisical Cli | Login Successful!</title>
|
||||||
|
<link rel='icon' href='/infisical.ico' />
|
||||||
|
</Head>
|
||||||
|
<div className='flex flex-col items-center justify-center text-gray-200 h-screen w-screen'>
|
||||||
|
<p className='text-4xl mt-32'>Head back to your terminal!</p>
|
||||||
|
<p className='mt-2 mb-1 text-lg'>
|
||||||
|
You've successfully logged into infisical-cli
|
||||||
|
</p>
|
||||||
|
<Image
|
||||||
|
src='/images/dragon-404.svg'
|
||||||
|
height={554}
|
||||||
|
width={942}
|
||||||
|
alt='infisical dragon - page not found'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user