Skip to content

Commit

Permalink
Repair register new user command
Browse files Browse the repository at this point in the history
Signed-off-by: keliramu <[email protected]>
  • Loading branch information
keliramu committed Dec 19, 2024
1 parent 9449530 commit 128c729
Show file tree
Hide file tree
Showing 31 changed files with 419 additions and 895 deletions.
2 changes: 0 additions & 2 deletions ci/generate_protobuf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ protoc --go_opt=module=github.com/NordSecurity/nordvpn-linux --go_out=. protobuf
protoc --go_opt=module=github.com/NordSecurity/nordvpn-linux --go_out=. protobuf/daemon/logout.proto -I protobuf/daemon
protoc --go_opt=module=github.com/NordSecurity/nordvpn-linux --go_out=. protobuf/daemon/login_with_token.proto -I protobuf/daemon
protoc --go_opt=module=github.com/NordSecurity/nordvpn-linux --go_out=. protobuf/daemon/ping.proto -I protobuf/daemon
protoc --go_opt=module=github.com/NordSecurity/nordvpn-linux --go_out=. protobuf/daemon/plans.proto -I protobuf/daemon
protoc --go_opt=module=github.com/NordSecurity/nordvpn-linux --go_out=. protobuf/daemon/rate.proto -I protobuf/daemon
protoc --go_opt=module=github.com/NordSecurity/nordvpn-linux --go_out=. protobuf/daemon/register.proto -I protobuf/daemon
protoc --go_opt=module=github.com/NordSecurity/nordvpn-linux --go_out=. protobuf/daemon/set.proto -I protobuf/daemon
protoc --go_opt=module=github.com/NordSecurity/nordvpn-linux --go_out=. protobuf/daemon/settings.proto -I protobuf/daemon
protoc --go_opt=module=github.com/NordSecurity/nordvpn-linux --go_out=. protobuf/daemon/status.proto -I protobuf/daemon
Expand Down
12 changes: 0 additions & 12 deletions cli/browser.go

This file was deleted.

29 changes: 20 additions & 9 deletions cli/cli_click.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"net/url"
"os"
"strings"
"time"

"github.com/NordSecurity/nordvpn-linux/daemon/pb"
Expand Down Expand Up @@ -54,8 +55,9 @@ func (c *cmd) Click(ctx *cli.Context) (err error) {
return formatError(err)
}

if url.Scheme == "nordvpn" {
if url.Host == "claim-online-purchase" {
if strings.ToLower(url.Scheme) == "nordvpn" {
switch strings.ToLower(url.Host) {
case "claim-online-purchase":
resp, err := c.client.ClaimOnlinePurchase(context.Background(), &pb.Empty{})
if err != nil {
return formatError(err)
Expand All @@ -67,17 +69,26 @@ func (c *cmd) Click(ctx *cli.Context) (err error) {

color.Green(ClaimOnlinePurchaseSuccess)
return nil
}

// if arg is given
// run the same as: login --callback %arg
if err := c.oauth2(ctx); err != nil {
return formatError(err)
case "login":
// login can be regular, or after new account setup & vpn service purchase (signup)
regularLogin := true
if strings.ToLower(url.Query().Get("action")) == "signup" {
regularLogin = false
}

// if arg is given
// run the same as: login --callback %arg
if err := c.oauth2(ctx, regularLogin); err != nil {
return formatError(err)
}
return nil
}
}
} else {
cli.ShowAppHelp(ctx)
}

// for all unhandled cases
cli.ShowAppHelp(ctx)

return nil
}
18 changes: 13 additions & 5 deletions cli/cli_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (c *cmd) Login(ctx *cli.Context) error {
}

if ctx.IsSet(flagLoginCallback) {
return c.oauth2(ctx)
return c.oauth2(ctx, true)
}

if ctx.IsSet(flagToken) {
Expand All @@ -44,7 +44,9 @@ func (c *cmd) Login(ctx *cli.Context) error {

cl, err := c.client.LoginOAuth2(
context.Background(),
&pb.Empty{},
&pb.LoginOAuth2Request{
Type: pb.LoginType_LoginType_LOGIN,
},
)
if err != nil {
return formatError(err)
Expand Down Expand Up @@ -102,7 +104,7 @@ func LoginRespHandler(ctx *cli.Context, resp *pb.LoginResponse) error {
}

// oauth2 is called by the browser during login via OAuth2.
func (c *cmd) oauth2(ctx *cli.Context) error {
func (c *cmd) oauth2(ctx *cli.Context, regularLogin bool) error {
if ctx.NArg() != 1 {
return formatError(errors.New("expected a url"))
}
Expand All @@ -116,8 +118,14 @@ func (c *cmd) oauth2(ctx *cli.Context) error {
return formatError(errors.New("expected a url with nordvpn scheme"))
}

_, err = c.client.LoginOAuth2Callback(context.Background(), &pb.String{
Data: url.Query().Get("exchange_token"),
loginType := pb.LoginType_LoginType_LOGIN
if !regularLogin {
loginType = pb.LoginType_LoginType_SIGNUP
}

_, err = c.client.LoginOAuth2Callback(context.Background(), &pb.LoginOAuth2CallbackRequest{
Token: url.Query().Get("exchange_token"),
Type: loginType,
})
if err != nil {
return formatError(err)
Expand Down
69 changes: 18 additions & 51 deletions cli/cli_register.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@ package cli

import (
"context"
"errors"
"fmt"
"sort"
"io"

"github.com/NordSecurity/nordvpn-linux/client"
"github.com/NordSecurity/nordvpn-linux/daemon/pb"
"github.com/NordSecurity/nordvpn-linux/internal"

"github.com/fatih/color"
"github.com/urfave/cli/v2"
Expand All @@ -18,57 +14,28 @@ import (
const RegisterUsageText = "Registers a new user account"

func (c *cmd) Register(ctx *cli.Context) error {
email, password, err := ReadCredentialsFromTerminal()
cl, err := c.client.LoginOAuth2(
context.Background(),
&pb.LoginOAuth2Request{
Type: pb.LoginType_LoginType_SIGNUP,
},
)
if err != nil {
return formatError(err)
}

resp, err := c.client.Register(context.Background(), &pb.RegisterRequest{
Email: email,
Password: password,
})
if err != nil {
return formatError(err)
}

switch resp.Type {
case internal.CodeSuccess:
color.Green(AccountCreationSuccess)
case internal.CodeBadRequest:
err = errors.New(AccountInvalidData)
case internal.CodeConflict:
err = errors.New(AccountEmailTaken)
case internal.CodeInternalError:
err = errors.New(AccountInternalError)
case internal.CodeFailure:
err = internal.ErrUnhandled
}

if err != nil {
return formatError(err)
}

planResp, err := c.client.Plans(context.Background(), &pb.Empty{})
if err != nil {
color.Red("Failed to retrieve subscription plans. Please finish the registration in NordVPN website.")
return browse(client.SubscriptionURL)
}

plans := planResp.GetPlans()
// sort plans by cost in ascending order
sort.Slice(plans, func(i, j int) bool {
costI := plans[i].GetCost()
costJ := plans[j].GetCost()
// this is done to avoid string -> int conversions
if len(costI) == len(costJ) {
return costI < costJ
for {
resp, err := cl.Recv()
if err != nil {
if err == io.EOF {
break
}
return formatError(err)
}
if url := resp.GetData(); url != "" {
color.Green("Continue in the browser: %s", url)
}
return len(costI) < len(costJ)
})
for i, plan := range plans {
description := fmt.Sprintf("%s for %s %s", plan.GetTitle(), plan.GetCost(), plan.GetCurrency())
fmt.Printf("%d) %s\n", i+1, description)
}

return browse(client.SubscriptionURL)
return nil
}
10 changes: 7 additions & 3 deletions core/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

// Authentication is responsible for verifying user's identity.
type Authentication interface {
Login() (string, error)
Login(bool) (string, error)
Token(string) (*LoginResponse, error)
}

Expand All @@ -36,7 +36,7 @@ func NewOAuth2(client *http.Client, baseURL string) *OAuth2 {
}
}

func (o *OAuth2) Login() (string, error) {
func (o *OAuth2) Login(regularLogin bool) (string, error) {
o.Lock()
defer o.Unlock()

Expand All @@ -52,7 +52,11 @@ func (o *OAuth2) Login() (string, error) {

query := url.Values{}
query.Add("challenge", o.challenge)
query.Add("preferred_flow", "login")
if regularLogin {
query.Add("preferred_flow", "login")
} else {
query.Add("preferred_flow", "registration")
}
query.Add("redirect_flow", "default")
path.RawQuery = query.Encode()
log.Println("oauth2 login url", path.String())
Expand Down
47 changes: 38 additions & 9 deletions core/authentication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package core
import (
"net/http"
"net/http/httptest"
"net/url"
"os"
"strings"
"testing"
Expand All @@ -16,15 +17,19 @@ func TestOAuth2_Login(t *testing.T) {
category.Set(t, category.Unit)

tests := []struct {
name string
handler http.HandlerFunc
expectedURL string
hasError bool
name string
handler http.HandlerFunc
regularLogin bool
expectedURL string
hasError bool
}{
{
name: http.StatusText(http.StatusOK),
handler: func(rw http.ResponseWriter, r *http.Request) {
assert.True(t, strings.HasPrefix(r.URL.String(), urlOAuth2Login))
url, err := url.Parse(r.URL.String())
assert.NoError(t, err)
assert.Equal(t, url.Path, urlOAuth2Login)
assert.True(t, url.Query().Get("preferred_flow") == "login")
data, err := os.ReadFile("testdata/login_200.json")
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
Expand All @@ -33,12 +38,16 @@ func TestOAuth2_Login(t *testing.T) {
rw.WriteHeader(http.StatusOK)
rw.Write(data)
},
expectedURL: "https://api.nordvpn.com/v1/users/oauth/login-redirect?attempt=bfeb71e5-6c9b-459b-bc50-40d0d0186bc4",
regularLogin: true,
expectedURL: "https://api.nordvpn.com/v1/users/oauth/login-redirect?attempt=bfeb71e5-6c9b-459b-bc50-40d0d0186bc4",
},
{
name: http.StatusText(http.StatusBadRequest),
handler: func(rw http.ResponseWriter, r *http.Request) {
assert.True(t, strings.HasPrefix(r.URL.String(), urlOAuth2Login))
url, err := url.Parse(r.URL.String())
assert.NoError(t, err)
assert.Equal(t, url.Path, urlOAuth2Login)
assert.True(t, url.Query().Get("preferred_flow") == "login")
data, err := os.ReadFile("testdata/login_400.json")
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
Expand All @@ -47,7 +56,27 @@ func TestOAuth2_Login(t *testing.T) {
rw.WriteHeader(http.StatusBadRequest)
rw.Write(data)
},
hasError: true,
regularLogin: true,
hasError: true,
},
{
name: http.StatusText(http.StatusOK),
handler: func(rw http.ResponseWriter, r *http.Request) {
url, err := url.Parse(r.URL.String())
assert.NoError(t, err)
assert.Equal(t, url.Path, urlOAuth2Login)
assert.True(t, url.Query().Get("preferred_flow") == "registration")
data, err := os.ReadFile("testdata/login_200.json")
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
return
}
rw.WriteHeader(http.StatusOK)
rw.Write(data)
},
regularLogin: false,
expectedURL: "https://api.nordvpn.com/v1/users/oauth/login-redirect?attempt=bfeb71e5-6c9b-459b-bc50-40d0d0186bc4",
hasError: false,
},
}

Expand All @@ -57,7 +86,7 @@ func TestOAuth2_Login(t *testing.T) {
defer server.Close()

api := NewOAuth2(http.DefaultClient, server.URL)
url, err := api.Login()
url, err := api.Login(test.regularLogin)
assert.Equal(t, test.hasError, err != nil)
if test.hasError {
assert.True(t, strings.Contains(err.Error(), test.name))
Expand Down
Loading

0 comments on commit 128c729

Please sign in to comment.