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

V18 Major #1370

Merged
merged 9 commits into from
Aug 17, 2023
4 changes: 2 additions & 2 deletions .github/actions/test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ inputs:
runs:
using: "composite"
steps:
- name: Setup Node.js 14
- name: Setup Node.js 16
if: ${{ env.os_value == 'ubuntu-20.04' }}
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 16

- name: Setup Node.js lts
if: ${{ env.os_value != 'ubuntu-20.04' }}
Expand Down
63 changes: 23 additions & 40 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,9 +429,8 @@ const sdk = fromSharedOptions();
* [.loginWithToken(authToken)](#balena.auth.loginWithToken) ⇒ <code>Promise</code>
* [.isLoggedIn()](#balena.auth.isLoggedIn) ⇒ <code>Promise</code>
* [.getToken()](#balena.auth.getToken) ⇒ <code>Promise</code>
* [.getUserId()](#balena.auth.getUserId) ⇒ <code>Promise</code>
* [.getUserActorId()](#balena.auth.getUserActorId) ⇒ <code>Promise</code>
* [.getEmail()](#balena.auth.getEmail) ⇒ <code>Promise</code>
* [.getUserInfo()](#balena.auth.getUserInfo) ⇒ <code>Promise</code>
* [.getActorId()](#balena.auth.getActorId) ⇒ <code>Promise</code>
* [.logout()](#balena.auth.logout) ⇒ <code>Promise</code>
* [.register(credentials)](#balena.auth.register) ⇒ <code>Promise</code>
* [.verifyEmail(verificationPayload)](#balena.auth.verifyEmail) ⇒ <code>Promise</code>
Expand Down Expand Up @@ -6483,9 +6482,8 @@ balena.models.billing.downloadInvoice(orgId, '0000').then(function(stream) {
* [.loginWithToken(authToken)](#balena.auth.loginWithToken) ⇒ <code>Promise</code>
* [.isLoggedIn()](#balena.auth.isLoggedIn) ⇒ <code>Promise</code>
* [.getToken()](#balena.auth.getToken) ⇒ <code>Promise</code>
* [.getUserId()](#balena.auth.getUserId) ⇒ <code>Promise</code>
* [.getUserActorId()](#balena.auth.getUserActorId) ⇒ <code>Promise</code>
* [.getEmail()](#balena.auth.getEmail) ⇒ <code>Promise</code>
* [.getUserInfo()](#balena.auth.getUserInfo) ⇒ <code>Promise</code>
* [.getActorId()](#balena.auth.getActorId) ⇒ <code>Promise</code>
* [.logout()](#balena.auth.logout) ⇒ <code>Promise</code>
* [.register(credentials)](#balena.auth.register) ⇒ <code>Promise</code>
* [.verifyEmail(verificationPayload)](#balena.auth.verifyEmail) ⇒ <code>Promise</code>
Expand Down Expand Up @@ -6630,19 +6628,19 @@ balena.auth.loginWithToken(token);
<a name="balena.auth.whoami"></a>

#### auth.whoami() ⇒ <code>Promise</code>
This will only work if you used [login](#balena.auth.login) to log in.
This will only work if you used [login](#balena.auth.login) or [loginWithToken](#balena.auth.loginWithToken) to log in.

**Kind**: static method of [<code>auth</code>](#balena.auth)
**Summary**: Return current logged in username
**Summary**: Return current logged in information
**Access**: public
**Fulfil**: <code>(String\|undefined)</code> - username, if it exists
**Fulfil**: <code>(Object\|undefined)</code> - actor information, if it exists
**Example**
```js
balena.auth.whoami().then(function(username) {
if (!username) {
balena.auth.whoami().then(function(result) {
if (!result) {
console.log('I\'m not logged in!');
} else {
console.log('My username is:', username);
console.log('My result is:', result);
}
});
```
Expand Down Expand Up @@ -6740,49 +6738,34 @@ balena.auth.getToken().then(function(token) {
console.log(token);
});
```
<a name="balena.auth.getUserId"></a>
<a name="balena.auth.getUserInfo"></a>

#### auth.getUserId() ⇒ <code>Promise</code>
#### auth.getUserInfo() ⇒ <code>Promise</code>
This will only work if you used [login](#balena.auth.login) to log in.

**Kind**: static method of [<code>auth</code>](#balena.auth)
**Summary**: Get current logged in user's id
**Summary**: Get current logged in user's info
**Access**: public
**Fulfil**: <code>Number</code> - user id
**Fulfil**: <code>Object</code> - user info
**Example**
```js
balena.auth.getUserId().then(function(userId) {
console.log(userId);
balena.auth.getUserInfo().then(function(userInfo) {
console.log(userInfo);
});
```
<a name="balena.auth.getUserActorId"></a>

#### auth.getUserActorId() ⇒ <code>Promise</code>
This will only work if you used [login](#balena.auth.login) to log in.
<a name="balena.auth.getActorId"></a>

**Kind**: static method of [<code>auth</code>](#balena.auth)
**Summary**: Get current logged in user's actor id
**Access**: public
**Fulfil**: <code>Number</code> - user id
**Example**
```js
balena.auth.getUserActorId().then(function(userActorId) {
console.log(userActorId);
});
```
<a name="balena.auth.getEmail"></a>

#### auth.getEmail() ⇒ <code>Promise</code>
This will only work if you used [login](#balena.auth.login) to log in.
#### auth.getActorId() ⇒ <code>Promise</code>
This will only work if you used [login](#balena.auth.login) or [loginWithToken](#balena.auth.loginWithToken) to log in.

**Kind**: static method of [<code>auth</code>](#balena.auth)
**Summary**: Get current logged in user's email
**Summary**: Get current logged in actor id
**Access**: public
**Fulfil**: <code>String</code> - user email
**Fulfil**: <code>Number</code> - actor id
**Example**
```js
balena.auth.getEmail().then(function(email) {
console.log(email);
balena.auth.getActorId().then(function(actorId) {
console.log(actorId);
});
```
<a name="balena.auth.logout"></a>
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ $ npm install --save balena-sdk

## Platforms

We currently support NodeJS (14+) and the browser.
We currently support NodeJS (16+) and the browser.

The following features are node-only:
- OS image streaming download (`balena.models.os.download`),
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"author": "Juan Cruz Viotti <[email protected]>",
"license": "Apache-2.0",
"engines": {
"node": ">=14.0"
"node": ">=16.0"
},
"devDependencies": {
"@balena/lint": "^6.1.1",
Expand Down Expand Up @@ -119,7 +119,7 @@
"dependencies": {
"@balena/es-version": "^1.0.0",
"@types/json-schema": "^7.0.9",
"@types/node": "^14.0.0",
"@types/node": "^16.0.0",
"abortcontroller-polyfill": "^1.7.1",
"balena-auth": "^5.1.0",
"balena-errors": "^4.8.0",
Expand Down
120 changes: 47 additions & 73 deletions src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
import * as errors from 'balena-errors';
import memoizee from 'memoizee';
import type { InjectedDependenciesParam, InjectedOptionsParam } from '.';
import { UserInfo, WhoamiResult } from './types/auth';

const getAuth = function (
deps: InjectedDependenciesParam,
Expand Down Expand Up @@ -65,62 +66,55 @@ const getAuth = function (
opts,
);

interface WhoamiResult {
id: number;
username: string;
email: string;
}

const userWhoami = async () => {
const actorWhoami = async () => {
const { body } = await request.send<WhoamiResult>({
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);
}
};

/**
* @summary Return current logged in username
* @summary Return current logged in information
* @name whoami
* @public
* @function
* @memberof balena.auth
*
* @description This will only work if you used {@link balena.auth.login} to log in.
* @description This will only work if you used {@link balena.auth.login} or {@link balena.auth.loginWithToken} to log in.
*
* @fulfil {(String|undefined)} - username, if it exists
* @fulfil {(Object|undefined)} - actor information, if it exists
* @returns {Promise}
*
* @example
* balena.auth.whoami().then(function(username) {
* if (!username) {
* balena.auth.whoami().then(function(result) {
* if (!result) {
* console.log('I\'m not logged in!');
* } else {
* console.log('My username is:', username);
* console.log('My result is:', result);
* }
* });
*/
async function whoami(): Promise<string | undefined> {
async function whoami(): Promise<WhoamiResult | undefined> {
try {
const userDetails = await getUserDetails();
return userDetails?.username;
return await getActorDetails();
} catch (err) {
if (err instanceof errors.BalenaNotLoggedIn) {
return;
Expand Down Expand Up @@ -203,7 +197,7 @@ const getAuth = function (
email: string;
password: string;
}): Promise<void> {
memoizedUserWhoami.clear();
memoizedActorWhoami.clear();
const token = await authenticate(credentials);
await auth.setKey(token);
}
Expand All @@ -224,7 +218,7 @@ const getAuth = function (
* balena.auth.loginWithToken(authToken);
*/
function loginWithToken(authToken: string): Promise<void> {
memoizedUserWhoami.clear();
memoizedActorWhoami.clear();
return auth.setKey(authToken);
}

Expand All @@ -249,7 +243,7 @@ const getAuth = function (
*/
async function isLoggedIn(): Promise<boolean> {
try {
await getUserDetails(true);
await getActorDetails(true);
return true;
} catch (err) {
if (
Expand Down Expand Up @@ -286,75 +280,56 @@ const getAuth = function (
}

/**
* @summary Get current logged in user's id
* @name getUserId
* @summary Get current logged in user's info
* @name getUserInfo
* @public
* @function
* @memberof balena.auth
*
* @description This will only work if you used {@link balena.auth.login} to log in.
*
* @fulfil {Number} - user id
* @fulfil {Object} - user info
* @returns {Promise}
*
* @example
* balena.auth.getUserId().then(function(userId) {
* console.log(userId);
* balena.auth.getUserInfo().then(function(userInfo) {
* console.log(userInfo);
* });
*/
async function getUserId(): Promise<number> {
const { id } = await getUserDetails();
return id;
}
async function getUserInfo(): Promise<UserInfo> {
const actor = await getActorDetails();

/**
* @summary Get current logged in user's actor id
* @name getUserActorId
* @public
* @function
* @memberof balena.auth
*
* @description This will only work if you used {@link balena.auth.login} to log in.
*
* @fulfil {Number} - user id
* @returns {Promise}
*
* @example
* balena.auth.getUserActorId().then(function(userActorId) {
* console.log(userActorId);
* });
*/
async function getUserActorId(): Promise<number> {
const { actor } = (await pine.get({
resource: 'user',
id: await getUserId(),
options: {
$select: 'actor',
},
}))!;
return actor;
if (actor.actorType !== 'user') {
throw new Error(
'The authentication credentials in use are not of a user',
);
}
return {
id: actor.actorTypeId,
email: actor.email,
username: actor.username,
};
}

/**
* @summary Get current logged in user's email
* @name getEmail
* @summary Get current logged in actor id
* @name getActorId
* @public
* @function
* @memberof balena.auth
*
* @description This will only work if you used {@link balena.auth.login} to log in.
* @description This will only work if you used {@link balena.auth.login} or {@link balena.auth.loginWithToken} to log in.
*
* @fulfil {String} - user email
* @fulfil {Number} - actor id
* @returns {Promise}
*
* @example
* balena.auth.getEmail().then(function(email) {
* console.log(email);
* balena.auth.getActorId().then(function(actorId) {
* console.log(actorId);
* });
*/
async function getEmail(): Promise<string> {
const { email } = await getUserDetails();
return email;
async function getActorId(): Promise<number> {
return (await getActorDetails()).id;
}

/**
Expand All @@ -370,7 +345,7 @@ const getAuth = function (
* balena.auth.logout();
*/
function logout(): Promise<void> {
memoizedUserWhoami.clear();
memoizedActorWhoami.clear();
return auth.removeKey();
}

Expand Down Expand Up @@ -474,7 +449,7 @@ const getAuth = function (
*
*/
async function requestVerificationEmail() {
const id = await getUserId();
const { id } = await getUserInfo();
await pine.patch({
resource: 'user',
id,
Expand All @@ -492,9 +467,8 @@ const getAuth = function (
loginWithToken,
isLoggedIn,
getToken,
getUserId,
getUserActorId,
getEmail,
getActorId,
getUserInfo,
logout,
register,
verifyEmail,
Expand Down
Loading
Loading