Skip to content

Commit

Permalink
Merge 0f73b19 into f8670d0
Browse files Browse the repository at this point in the history
  • Loading branch information
bassosimone committed Dec 9, 2019
2 parents f8670d0 + 0f73b19 commit f006052
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 16 deletions.
22 changes: 9 additions & 13 deletions internal/orchestra/login/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ import (

// Config contains configs for logging in with the OONI orchestra.
type Config struct {
BaseURL string
ClientID string
HTTPClient *http.Client
Logger log.Logger
Password string
UserAgent string
BaseURL string
Credentials Credentials
HTTPClient *http.Client
Logger log.Logger
UserAgent string
}

type request struct {
Username string `json:"username"`
// Credentials contains the login credentials
type Credentials struct {
ClientID string `json:"username"`
Password string `json:"password"`
}

Expand All @@ -33,17 +33,13 @@ type Auth struct {

// Do logs this probe in with OONI orchestra
func Do(ctx context.Context, config Config) (*Auth, error) {
req := &request{
Password: config.Password,
Username: config.ClientID,
}
var resp Auth
err := (&jsonapi.Client{
BaseURL: config.BaseURL,
HTTPClient: config.HTTPClient,
Logger: config.Logger,
UserAgent: config.UserAgent,
}).Create(ctx, "/api/v1/login", req, &resp)
}).Create(ctx, "/api/v1/login", config.Credentials, &resp)
if err != nil {
return nil, err
}
Expand Down
81 changes: 81 additions & 0 deletions internal/orchestra/statefile/statefile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Package statefile defines the state file
package statefile

import (
"errors"
"sync"
"time"

"github.com/ooni/probe-engine/internal/orchestra/login"
)

// State is the state stored inside the state file
type State struct {
ClientID string
Expire time.Time
Password string
Token string
}

// Auth returns an authentication structure, if possible, otherwise
// it returns nil, meaning that you should login again.
func (s State) Auth() *login.Auth {
if s.Token == "" {
return nil
}
if time.Now().Add(30 * time.Second).After(s.Expire) {
return nil
}
return &login.Auth{
Expire: s.Expire,
Token: s.Token,
}
}

// Credentials returns login credentials, if possible, otherwise it
// returns nil, meaning that you should create an account.
func (s State) Credentials() *login.Credentials {
if s.ClientID == "" {
return nil
}
if s.Password == "" {
return nil
}
return &login.Credentials{
ClientID: s.ClientID,
Password: s.Password,
}
}

// StateFile is a generic state file
type StateFile interface {
Set(*State) error
Get() (*State, error)
}

type memory struct {
state State
mu sync.Mutex
}

// NewMemory creates a new state file in memory
func NewMemory(workdir string) StateFile {
return &memory{}
}

func (sf *memory) Set(s *State) error {
if s == nil {
return errors.New("passed nil pointer")
}
sf.mu.Lock()
defer sf.mu.Unlock()
sf.state = *s
return nil
}

func (sf *memory) Get() (*State, error) {
sf.mu.Lock()
defer sf.mu.Unlock()
state := sf.state
return &state, nil
}
94 changes: 94 additions & 0 deletions internal/orchestra/statefile/statefile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package statefile

import (
"testing"
"time"
)

func TestUnitStateAuth(t *testing.T) {
t.Run("with no Token", func(t *testing.T) {
state := State{Expire: time.Now().Add(10 * time.Hour)}
if state.Auth() != nil {
t.Fatal("expected nil here")
}
})
t.Run("with expired Token", func(t *testing.T) {
state := State{
Expire: time.Now().Add(-1 * time.Hour),
Token: "xx-x-xxx-xx",
}
if state.Auth() != nil {
t.Fatal("expected nil here")
}
})
t.Run("with good Token", func(t *testing.T) {
state := State{
Expire: time.Now().Add(10 * time.Hour),
Token: "xx-x-xxx-xx",
}
if state.Auth() == nil {
t.Fatal("expected valid auth here")
}
})
}

func TestUnitStateCredentials(t *testing.T) {
t.Run("with no ClientID", func(t *testing.T) {
state := State{}
if state.Credentials() != nil {
t.Fatal("expected nil here")
}
})
t.Run("with no Password", func(t *testing.T) {
state := State{
ClientID: "xx-x-xxx-xx",
}
if state.Credentials() != nil {
t.Fatal("expected nil here")
}
})
t.Run("with all good", func(t *testing.T) {
state := State{
ClientID: "xx-x-xxx-xx",
Password: "xx",
}
if state.Credentials() == nil {
t.Fatal("expected valid auth here")
}
})
}

func TestUnitStateFileMemory(t *testing.T) {
sf := NewMemory("/tmp")
if sf == nil {
t.Fatal("expected non nil pointer here")
}
if err := sf.Set(nil); err == nil {
t.Fatal("expected an error here")
}
s := State{
Expire: time.Now(),
Password: "xy",
Token: "abc",
ClientID: "xx",
}
if err := sf.Set(&s); err != nil {
t.Fatal(err)
}
os, err := sf.Get()
if err != nil {
t.Fatal(err)
}
if s.ClientID != os.ClientID {
t.Fatal("the ClientID field has changed")
}
if !s.Expire.Equal(os.Expire) {
t.Fatal("the Expire field has changed")
}
if s.Password != os.Password {
t.Fatal("the Password field has changed")
}
if s.Token != os.Token {
t.Fatal("the Token field has changed")
}
}
8 changes: 5 additions & 3 deletions internal/orchestra/testorchestra/testorchestra.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ func Register() (string, error) {
// information on success, and an error on failure.
func Login(clientID string) (*login.Auth, error) {
return login.Do(context.Background(), login.Config{
BaseURL: "https://ps-test.ooni.io",
ClientID: clientID,
BaseURL: "https://ps-test.ooni.io",
Credentials: login.Credentials{
ClientID: clientID,
Password: password,
},
HTTPClient: http.DefaultClient,
Logger: log.Log,
Password: password,
UserAgent: "miniooni/0.1.0-dev",
})
}
Expand Down

0 comments on commit f006052

Please sign in to comment.