From 037205ff10934ca5344cccd0447eb4d9a3c11a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ot=C3=A1vio=20Jacobi?= Date: Tue, 8 Aug 2023 10:27:32 -0300 Subject: [PATCH] Replace /user/v1/whoami for /actor/v1/whoami Change-type: major --- src/auth.ts | 44 ++++++++++++++++------------------ src/index.ts | 1 + src/types/auth.ts | 26 ++++++++++++++++++++ tests/integration/auth.spec.ts | 13 +++++++--- 4 files changed, 58 insertions(+), 26 deletions(-) create mode 100644 src/types/auth.ts diff --git a/src/auth.ts b/src/auth.ts index 1440f7ffd..c883a89b2 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -17,6 +17,7 @@ limitations under the License. import * as errors from 'balena-errors'; import memoizee from 'memoizee'; import type { InjectedDependenciesParam, InjectedOptionsParam } from '.'; +import { WhoamiResult } from './types/auth'; const getAuth = function ( deps: InjectedDependenciesParam, @@ -65,32 +66,26 @@ const getAuth = function ( opts, ); - interface WhoamiResult { - id: number; - username: string; - email: string; - } - - const userWhoami = async () => { + const actorWhoami = async () => { const { body } = await request.send({ method: 'GET', - url: '/user/v1/whoami', + url: '/actor/v1/whoami', baseUrl: apiUrl, }); return body; }; - const memoizedUserWhoami = memoizee(userWhoami, { + const memoizedActorWhoami = memoizee(actorWhoami, { primitive: true, promise: true, }); - const getUserDetails = async (noCache = false) => { + const getActorDetails = async (noCache = false) => { if (noCache) { - memoizedUserWhoami.clear(); + memoizedActorWhoami.clear(); } try { - return await memoizedUserWhoami(); + return await memoizedActorWhoami(); } catch (err) { throw normalizeAuthError(err); } @@ -117,10 +112,9 @@ const getAuth = function ( * } * }); */ - async function whoami(): Promise { + async function whoami(): Promise { try { - const userDetails = await getUserDetails(); - return userDetails?.username; + return await getActorDetails(); } catch (err) { if (err instanceof errors.BalenaNotLoggedIn) { return; @@ -203,7 +197,7 @@ const getAuth = function ( email: string; password: string; }): Promise { - memoizedUserWhoami.clear(); + memoizedActorWhoami.clear(); const token = await authenticate(credentials); await auth.setKey(token); } @@ -224,7 +218,7 @@ const getAuth = function ( * balena.auth.loginWithToken(authToken); */ function loginWithToken(authToken: string): Promise { - memoizedUserWhoami.clear(); + memoizedActorWhoami.clear(); return auth.setKey(authToken); } @@ -249,7 +243,7 @@ const getAuth = function ( */ async function isLoggedIn(): Promise { try { - await getUserDetails(true); + await getActorDetails(true); return true; } catch (err) { if ( @@ -303,7 +297,7 @@ const getAuth = function ( * }); */ async function getUserId(): Promise { - const { id } = await getUserDetails(); + const { id } = await getActorDetails(); return id; } @@ -352,9 +346,13 @@ const getAuth = function ( * console.log(email); * }); */ - async function getEmail(): Promise { - const { email } = await getUserDetails(); - return email; + async function getEmail(): Promise { + const result = await getActorDetails(); + + if (result.actorType === 'user') { + return result.email; + } + return null; } /** @@ -370,7 +368,7 @@ const getAuth = function ( * balena.auth.logout(); */ function logout(): Promise { - memoizedUserWhoami.clear(); + memoizedActorWhoami.clear(); return auth.removeKey(); } diff --git a/src/index.ts b/src/index.ts index a7ade0143..0e5e2f883 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,6 +24,7 @@ export * from './types/models'; export * from './types/jwt'; export * from './types/contract'; export * from './types/user-invite'; +export * from './types/auth'; export type { Interceptor }; export type { diff --git a/src/types/auth.ts b/src/types/auth.ts new file mode 100644 index 000000000..b5f28acb9 --- /dev/null +++ b/src/types/auth.ts @@ -0,0 +1,26 @@ +export interface UserKeyWhoAmIResponse { + id: number; + actorType: 'user'; + actorTypeId: number; + username: string; + email: string | null; +} + +export interface ApplicationKeyWhoAmIResponse { + id: number; + actorType: 'application'; + actorTypeId: number; + slug: string; +} + +export interface DeviceKeyWhoAmIResponse { + id: number; + actorType: 'device'; + actorTypeId: number; + uuid: string; +} + +export type WhoamiResult = + | UserKeyWhoAmIResponse + | ApplicationKeyWhoAmIResponse + | DeviceKeyWhoAmIResponse; diff --git a/tests/integration/auth.spec.ts b/tests/integration/auth.spec.ts index fb2653361..179183798 100644 --- a/tests/integration/auth.spec.ts +++ b/tests/integration/auth.spec.ts @@ -10,6 +10,7 @@ import { givenLoggedInUserWithApiKey, loginUserWith2FA, } from './setup'; +import { UserKeyWhoAmIResponse } from '../../src'; describe('SDK authentication', function () { timeSuite(before); @@ -239,8 +240,11 @@ describe('SDK authentication', function () { }); describe('balena.auth.whoami()', () => { - it('should eventually be the username', async function () { - expect(await balena.auth.whoami()).to.equal(credentials.username); + it('should eventually be the user whoami response', async function () { + const whoamiResult = + (await balena.auth.whoami()) as UserKeyWhoAmIResponse; + expect(whoamiResult?.actorType).to.equal('user'); + expect(whoamiResult?.username).to.equal(credentials.username); }); }); @@ -285,7 +289,10 @@ describe('SDK authentication', function () { describe('balena.auth.whoami()', () => { it('should eventually be the username', async function () { - expect(await balena.auth.whoami()).to.equal(credentials.username); + const whoamiResult = + (await balena.auth.whoami()) as UserKeyWhoAmIResponse; + expect(whoamiResult?.actorType).to.equal('user'); + expect(whoamiResult?.username).to.equal(credentials.username); }); });