Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@internxt/sdk",
"author": "Internxt <hello@internxt.com>",
"version": "1.20.2",
"version": "1.21.0",
"description": "An sdk for interacting with Internxt's services",
"repository": {
"type": "git",
Expand Down
37 changes: 18 additions & 19 deletions src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,17 +189,19 @@ export class Auth {
* Tries to log in a user given its login details
* @param details
* @param cryptoProvider
* @param knownSecurityDetails Skips the internal `/auth/login` call if the caller already has it
*/
public async login(
details: LoginDetails,
cryptoProvider: CryptoProvider,
knownSecurityDetails?: SecurityDetails,
): Promise<{
token: Token;
newToken: Token;
user: UserSettings;
userTeam: TeamsSettings | null;
}> {
const securityDetails = await this.securityDetails(details.email);
const securityDetails = knownSecurityDetails ?? (await this.securityDetails(details.email));
const encryptedSalt = securityDetails.encryptedSalt;
const encryptedPasswordHash = cryptoProvider.encryptPasswordHash(details.password, encryptedSalt);
const keys = await cryptoProvider.generateKeys(details.password);
Expand Down Expand Up @@ -325,24 +327,21 @@ export class Auth {
* Returns general security details
* @param email
*/
public securityDetails(email: string): Promise<SecurityDetails> {
return this.client
.post<{
sKey: string;
tfa: boolean | null;
}>(
'/auth/login',
{
email: email,
},
this.basicHeaders(),
)
.then((data) => {
return {
encryptedSalt: data.sKey,
tfaEnabled: data.tfa === true,
};
});
public async securityDetails(email: string): Promise<SecurityDetails> {
const data = await this.client.post<{
sKey: string;
tfa: boolean | null;
}>(
'/auth/login',
{
email: email,
},
this.basicHeaders(),
);
return {
encryptedSalt: data.sKey,
tfaEnabled: data.tfa === true,
};
}

/**
Expand Down
57 changes: 57 additions & 0 deletions test/auth/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,63 @@ describe('# auth service tests', () => {
headers,
);
});

it('Should skip the securityDetails call when knownSecurityDetails is provided', async () => {
// Arrange
const { client, headers } = clientAndHeaders();
const loginDetails: LoginDetails = {
email: 'my_email',
password: 'password',
tfaCode: undefined,
};
const cryptoProvider: CryptoProvider = {
encryptPasswordHash: (password, encryptedSalt) => password + '-' + encryptedSalt,
generateKeys: () => {
const keys: Keys = {
ecc: {
publicKey: 'pub',
privateKeyEncrypted: 'priv',
},
kyber: {
publicKey: 'pubKyber',
privateKeyEncrypted: 'privKyber',
},
};
return Promise.resolve(keys);
},
};
const postStub = vi.spyOn(HttpClient.prototype, 'post').mockResolvedValueOnce({
user: {},
});

// Act
await client.login(loginDetails, cryptoProvider, {
encryptedSalt: 'known_encrypted_salt',
tfaEnabled: false,
});

// Assert
expect(postStub).toHaveBeenCalledTimes(1);
expect(postStub).toHaveBeenCalledWith(
'/auth/login/access',
{
email: loginDetails.email,
password: 'password-known_encrypted_salt',
tfa: loginDetails.tfaCode,
keys: {
ecc: {
publicKey: 'pub',
privateKey: 'priv',
},
kyber: {
publicKey: 'pubKyber',
privateKey: 'privKyber',
},
},
},
headers,
);
});
});

describe('-> loginWithoutKeys use case', () => {
Expand Down
Loading