Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Psg 5154 introduce new method names #98

Merged
merged 24 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions CHANGELOG.md
tdeshong marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@

All notable changes to this project will be documented in this file.

## [1.11.3] - 2024-11-30

### Added
- deprecated methods
- Passage.GetUser(userId: string): User
- Passage.GetUserByIdentifier(identifier: string): User
- Passage.ActivateUser(userId: string): User
- Passage.DeactivateUser(userId: string): User
- Passage.UpdateUser(userId: string, options: UpdateUserArgs): User
- Passage.CreateUser(args: CreateUserArgs): User
- Passage.DeleteUser(userId: string): boolean
- Passage.ListUserDevices(userId: string): WebAuthnDevice[]
- Passage.RevokeUserDevice(userId: string, deviceId: string): boolean
- Passage.ValidateAuthToken(authToken: string): string, bool
- added new methods
- Passage.User.Get(userId: string): User
- Passage.User.GetByIdentifier(identifier: string): User
- Passage.User.Activate(userId: string): User
- Passage.User.Deactivate(userId: string): User
- Passage.User.Update(userId: string, options: UpdateUserArgs): User
- Passage.User.Create(args: CreateUserArgs): User
- Passage.User.Delete(userId: string): boolean
- Passage.User.ListDevices(userId: string): WebAuthnDevice[]
- Passage.User.RevokeDevice(userId: string, deviceId: string): boolean
- Passage.ValidateJwt(authToken: string): string, bool

## [1.11.2] - 2024-10-24

### Added
Expand Down
6 changes: 6 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ type Config struct {
HeaderAuth bool
}

// Deprecated: will be replace with a different object in v2
tdeshong marked this conversation as resolved.
Show resolved Hide resolved
type App struct {
ID string
Config *Config
tdeshong marked this conversation as resolved.
Show resolved Hide resolved
User *AppUser
client *ClientWithResponses
jwksCacheSet jwk.Set
}

// Deprecated: Will be replaced with a different signature in v2
func New(appID string, config *Config) (*App, error) {
if config == nil {
config = &Config{}
Expand Down Expand Up @@ -53,9 +56,12 @@ func New(appID string, config *Config) (*App, error) {

app.jwksCacheSet = jwk.NewCachedSet(cache, url)

app.User = newAppUser(appID, app)

return &app, nil
}

// Deprecated: GetApp
tdeshong marked this conversation as resolved.
Show resolved Hide resolved
// GetApp gets information about an app
// returns App on success, error on failure
func (a *App) GetApp() (*AppInfo, error) {
Expand Down
81 changes: 81 additions & 0 deletions app_user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package passage

type PassageUser = User
type AppUser struct {
tdeshong marked this conversation as resolved.
Show resolved Hide resolved
appID string
app App
}

const (
UserIDDoesNotExist string = "passage User with ID \"%v\" does not exist"
IdentifierDoesNotExist string = "passage User with Identifier \"%v\" does not exist"
)

func newAppUser(appID string, app App) *AppUser {
tdeshong marked this conversation as resolved.
Show resolved Hide resolved
appUser := AppUser{
appID: appID,
app: app,
}

return &appUser
}

// Get gets a user using their userID
// returns user on success, error on failure
func (a *AppUser) Get(userID string) (*PassageUser, error) {
return a.app.GetUser(userID)
}

// GetByIdentifier gets a user using their identifier
// returns user on success, error on failure
func (a *AppUser) GetByIdentifier(identifier string) (*PassageUser, error) {
return a.app.GetUserByIdentifier(identifier)
}

// Activate activates a user using their userID
// returns user on success, error on failure
func (a *AppUser) Activate(userID string) (*PassageUser, error) {
return a.app.ActivateUser(userID)
}

// Deactivate deactivates a user using their userID
// returns user on success, error on failure
func (a *AppUser) Deactivate(userID string) (*PassageUser, error) {
return a.app.DeactivateUser(userID)
}

// Update receives an UpdateBody struct, updating the corresponding user's attribute(s)
// returns user on success, error on failure
func (a *AppUser) Update(userID string, updateBody UpdateBody) (*PassageUser, error) {
return a.app.UpdateUser(userID, updateBody)
}

// Delete deletes a user by their user string
// returns true on success, false and error on failure (bool, err)
func (a *AppUser) Delete(userID string) (bool, error) {
return a.app.DeleteUser(userID)
}

// Create receives a CreateUserBody struct, creating a user with provided values
// returns user on success, error on failure
func (a *AppUser) Create(createUserBody CreateUserBody) (*PassageUser, error) {
return a.app.CreateUser(createUserBody)
}

// ListDevices lists a user's devices
// returns a list of devices on success, error on failure
func (a *AppUser) ListDevices(userID string) ([]WebAuthnDevices, error) {
return a.app.ListUserDevices(userID)
}

// RevokeDevice gets a user using their userID
// returns a true success, error on failure
func (a *AppUser) RevokeDevice(userID, deviceID string) (bool, error) {
return a.app.RevokeUserDevice(userID, deviceID)
}

// Signout revokes a users refresh tokens
// returns true on success, error on failure
func (a *AppUser) SignOut(userID string) (bool, error) {
return a.app.SignOut(userID)
}
235 changes: 235 additions & 0 deletions app_user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
package passage_test

import (
"fmt"
"strings"
"testing"

"github.com/passageidentity/passage-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetInfo(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey,
})
require.Nil(t, err)

user, err := psg.User.Get(PassageUserID)
require.Nil(t, err)
assert.Equal(t, PassageUserID, user.ID)
}

func TestGetInfoByIdentifier(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey,
})
require.Nil(t, err)

createUserBody := passage.CreateUserBody{
Email: RandomEmail,
}

user, err := psg.User.Create(createUserBody)
require.Nil(t, err)
assert.Equal(t, RandomEmail, user.Email)

userByIdentifier, err := psg.User.GetByIdentifier(RandomEmail)
require.Nil(t, err)

userById, err := psg.User.Get(user.ID)
require.Nil(t, err)

assert.Equal(t, user.ID, userById.ID)

assert.Equal(t, userById, userByIdentifier)
}

func TestGetInfoByIdentifierEmailUpperCase(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey,
})
require.Nil(t, err)

createUserBody := passage.CreateUserBody{
Email: RandomEmail,
}

user, err := psg.User.Create(createUserBody)
require.Nil(t, err)
assert.Equal(t, RandomEmail, user.Email)

userByIdentifier, err := psg.User.GetByIdentifier(strings.ToUpper(RandomEmail))
require.Nil(t, err)

assert.Equal(t, user.ID, userByIdentifier.ID)
}

func TestGetInfoByIdentifierPhone(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey,
})
require.Nil(t, err)

phone := "+15005550007"
createUserBody := passage.CreateUserBody{
Phone: phone,
}

user, err := psg.User.Create(createUserBody)
require.Nil(t, err)
assert.Equal(t, phone, user.Phone)

userByIdentifier, err := psg.User.GetByIdentifier(phone)
require.Nil(t, err)

userById, err := psg.User.Get(user.ID)
require.Nil(t, err)

assert.Equal(t, user.ID, userById.ID)

assert.Equal(t, userById, userByIdentifier)
}

func TestGetInfoByIdentifierError(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey,
})
require.Nil(t, err)

_, err = psg.User.GetByIdentifier("error@passage.id")
require.NotNil(t, err)

expectedMessage := "passage User with Identifier \"error@passage.id\" does not exist"
assert.Contains(t, err.Error(), expectedMessage)
}

func TestActivate(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey, // An API_KEY environment variable is required for testing.
})
require.Nil(t, err)

user, err := psg.User.Activate(PassageUserID)
require.Nil(t, err)
assert.Equal(t, PassageUserID, user.ID)
assert.Equal(t, passage.StatusActive, user.Status)
}
func TestDeactivate(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey, // An API_KEY environment variable is required for testing.
})
require.Nil(t, err)

user, err := psg.User.Deactivate(PassageUserID)
require.Nil(t, err)
assert.Equal(t, PassageUserID, user.ID)
assert.Equal(t, passage.StatusInactive, user.Status)
}

func TestUpdate(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey, // An API_KEY environment variable is required for testing.
})
require.Nil(t, err)

updateBody := passage.UpdateBody{
Email: "updatedemail-gosdk@passage.id",
Phone: "+15005550012",
UserMetadata: map[string]interface{}{
"example1": "123",
},
}
user, err := psg.User.Update(PassageUserID, updateBody)
require.Nil(t, err)
assert.Equal(t, "updatedemail-gosdk@passage.id", user.Email)
assert.Equal(t, "+15005550012", user.Phone)
assert.Equal(t, "123", user.UserMetadata["example1"])

secondUpdateBody := passage.UpdateBody{
Email: "updatedemail-gosdk@passage.id",
Phone: "+15005550012",
UserMetadata: map[string]interface{}{
"example1": "456",
},
}
user, err = psg.User.Update(PassageUserID, secondUpdateBody)
require.Nil(t, err)
assert.Equal(t, "updatedemail-gosdk@passage.id", user.Email)
assert.Equal(t, "+15005550012", user.Phone)
assert.Equal(t, "456", user.UserMetadata["example1"])
}

func TestCreate(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey, // An API_KEY environment variable is required for testing.
})
require.Nil(t, err)

createUserBody := passage.CreateUserBody{
Email: RandomEmail,
}

user, err := psg.User.Create(createUserBody)
require.Nil(t, err)
assert.Equal(t, RandomEmail, user.Email)

CreatedUser = *user
}

func TestCreateWithMetadata(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey, // An API_KEY environment variable is required for testing.
})
require.Nil(t, err)

createUserBody := passage.CreateUserBody{
Email: fmt.Sprintf("1%v", RandomEmail),
UserMetadata: map[string]interface{}{
"example1": "test",
},
}

user, err := psg.User.Create(createUserBody)
require.Nil(t, err)
assert.Equal(t, "1"+RandomEmail, user.Email)
assert.Equal(t, "test", user.UserMetadata["example1"].(string))

CreatedUser = *user
}

func TestDelete(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey, // An API_KEY environment variable is required for testing.
})
require.Nil(t, err)

result, err := psg.User.Delete(CreatedUser.ID)
require.Nil(t, err)
assert.Equal(t, result, true)
}

func TestListDevices(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey,
})
require.Nil(t, err)

devices, err := psg.User.ListDevices(PassageUserID)
require.Nil(t, err)
assert.Equal(t, 2, len(devices))
}

// NOTE RevokeUserDevice is not tested because it is impossible to spoof webauthn to create a device to then revoke

func TestSignOut(t *testing.T) {
psg, err := passage.New(PassageAppID, &passage.Config{
APIKey: PassageApiKey, // An API_KEY environment variable is required for testing.
})
require.Nil(t, err)

result, err := psg.User.SignOut(PassageUserID)
require.Nil(t, err)
assert.Equal(t, result, true)
}
Loading