refactor: Rename AppAuthClient model as OAuthClient

This commit is contained in:
Faruk AYDIN
2024-12-18 17:42:04 +01:00
parent 4a4628e255
commit 8c4b67e147
61 changed files with 588 additions and 571 deletions

View File

@@ -3,10 +3,6 @@
exports[`Connection model > jsonSchema should have correct validations 1`] = `
{
"properties": {
"appAuthClientId": {
"format": "uuid",
"type": "string",
},
"createdAt": {
"type": "string",
},
@@ -31,6 +27,10 @@ exports[`Connection model > jsonSchema should have correct validations 1`] = `
"minLength": 1,
"type": "string",
},
"oauthClientId": {
"format": "uuid",
"type": "string",
},
"updatedAt": {
"type": "string",
},

View File

@@ -1,6 +1,6 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`AppAuthClient model > jsonSchema should have correct validations 1`] = `
exports[`OAuthClient model > jsonSchema should have correct validations 1`] = `
{
"properties": {
"active": {

View File

@@ -1,202 +0,0 @@
import { describe, it, expect, vi } from 'vitest';
import AES from 'crypto-js/aes.js';
import enc from 'crypto-js/enc-utf8.js';
import AppConfig from './app-config.js';
import AppAuthClient from './app-auth-client.js';
import Base from './base.js';
import appConfig from '../config/app.js';
import { createAppAuthClient } from '../../test/factories/app-auth-client.js';
describe('AppAuthClient model', () => {
it('tableName should return correct name', () => {
expect(AppAuthClient.tableName).toBe('app_auth_clients');
});
it('jsonSchema should have correct validations', () => {
expect(AppAuthClient.jsonSchema).toMatchSnapshot();
});
it('relationMappings should return correct associations', () => {
const relationMappings = AppAuthClient.relationMappings();
const expectedRelations = {
appConfig: {
relation: Base.BelongsToOneRelation,
modelClass: AppConfig,
join: {
from: 'app_auth_clients.app_key',
to: 'app_configs.key',
},
},
};
expect(relationMappings).toStrictEqual(expectedRelations);
});
describe('encryptData', () => {
it('should return undefined if eligibleForEncryption is not true', async () => {
vi.spyOn(
AppAuthClient.prototype,
'eligibleForEncryption'
).mockReturnValue(false);
const appAuthClient = new AppAuthClient();
expect(appAuthClient.encryptData()).toBeUndefined();
});
it('should encrypt formattedAuthDefaults and set it to authDefaults', async () => {
vi.spyOn(
AppAuthClient.prototype,
'eligibleForEncryption'
).mockReturnValue(true);
const formattedAuthDefaults = {
key: 'value',
};
const appAuthClient = new AppAuthClient();
appAuthClient.formattedAuthDefaults = formattedAuthDefaults;
appAuthClient.encryptData();
const expectedDecryptedValue = JSON.parse(
AES.decrypt(
appAuthClient.authDefaults,
appConfig.encryptionKey
).toString(enc)
);
expect(formattedAuthDefaults).toStrictEqual(expectedDecryptedValue);
expect(appAuthClient.authDefaults).not.toStrictEqual(
formattedAuthDefaults
);
});
it('should encrypt formattedAuthDefaults and remove formattedAuthDefaults', async () => {
vi.spyOn(
AppAuthClient.prototype,
'eligibleForEncryption'
).mockReturnValue(true);
const formattedAuthDefaults = {
key: 'value',
};
const appAuthClient = new AppAuthClient();
appAuthClient.formattedAuthDefaults = formattedAuthDefaults;
appAuthClient.encryptData();
expect(appAuthClient.formattedAuthDefaults).not.toBeDefined();
});
});
describe('decryptData', () => {
it('should return undefined if eligibleForDecryption is not true', () => {
vi.spyOn(
AppAuthClient.prototype,
'eligibleForDecryption'
).mockReturnValue(false);
const appAuthClient = new AppAuthClient();
expect(appAuthClient.decryptData()).toBeUndefined();
});
it('should decrypt authDefaults and set it to formattedAuthDefaults', async () => {
vi.spyOn(
AppAuthClient.prototype,
'eligibleForDecryption'
).mockReturnValue(true);
const formattedAuthDefaults = {
key: 'value',
};
const authDefaults = AES.encrypt(
JSON.stringify(formattedAuthDefaults),
appConfig.encryptionKey
).toString();
const appAuthClient = new AppAuthClient();
appAuthClient.authDefaults = authDefaults;
appAuthClient.decryptData();
expect(appAuthClient.formattedAuthDefaults).toStrictEqual(
formattedAuthDefaults
);
expect(appAuthClient.authDefaults).not.toStrictEqual(
formattedAuthDefaults
);
});
});
describe('eligibleForEncryption', () => {
it('should return true when formattedAuthDefaults property exists', async () => {
const appAuthClient = await createAppAuthClient();
expect(appAuthClient.eligibleForEncryption()).toBe(true);
});
it("should return false when formattedAuthDefaults property doesn't exist", async () => {
const appAuthClient = await createAppAuthClient();
delete appAuthClient.formattedAuthDefaults;
expect(appAuthClient.eligibleForEncryption()).toBe(false);
});
});
describe('eligibleForDecryption', () => {
it('should return true when authDefaults property exists', async () => {
const appAuthClient = await createAppAuthClient();
expect(appAuthClient.eligibleForDecryption()).toBe(true);
});
it("should return false when authDefaults property doesn't exist", async () => {
const appAuthClient = await createAppAuthClient();
delete appAuthClient.authDefaults;
expect(appAuthClient.eligibleForDecryption()).toBe(false);
});
});
it('$beforeInsert should call AppAuthClient.encryptData', async () => {
const appAuthClientBeforeInsertSpy = vi.spyOn(
AppAuthClient.prototype,
'encryptData'
);
await createAppAuthClient();
expect(appAuthClientBeforeInsertSpy).toHaveBeenCalledOnce();
});
it('$beforeUpdate should call AppAuthClient.encryptData', async () => {
const appAuthClient = await createAppAuthClient();
const appAuthClientBeforeUpdateSpy = vi.spyOn(
AppAuthClient.prototype,
'encryptData'
);
await appAuthClient.$query().patchAndFetch({ name: 'sample' });
expect(appAuthClientBeforeUpdateSpy).toHaveBeenCalledOnce();
});
it('$afterFind should call AppAuthClient.decryptData', async () => {
const appAuthClient = await createAppAuthClient();
const appAuthClientAfterFindSpy = vi.spyOn(
AppAuthClient.prototype,
'decryptData'
);
await appAuthClient.$query();
expect(appAuthClientAfterFindSpy).toHaveBeenCalledOnce();
});
});

View File

@@ -1,5 +1,5 @@
import App from './app.js';
import AppAuthClient from './app-auth-client.js';
import OAuthClient from './oauth-client.js';
import Base from './base.js';
class AppConfig extends Base {
@@ -24,12 +24,12 @@ class AppConfig extends Base {
};
static relationMappings = () => ({
appAuthClients: {
oauthClients: {
relation: Base.HasManyRelation,
modelClass: AppAuthClient,
modelClass: OAuthClient,
join: {
from: 'app_configs.key',
to: 'app_auth_clients.app_key',
to: 'oauth_clients.app_key',
},
},
});

View File

@@ -3,7 +3,7 @@ import { describe, it, expect } from 'vitest';
import Base from './base.js';
import AppConfig from './app-config.js';
import App from './app.js';
import AppAuthClient from './app-auth-client.js';
import OAuthClient from './oauth-client.js';
describe('AppConfig model', () => {
it('tableName should return correct name', () => {
@@ -22,12 +22,12 @@ describe('AppConfig model', () => {
const relationMappings = AppConfig.relationMappings();
const expectedRelations = {
appAuthClients: {
oauthClients: {
relation: Base.HasManyRelation,
modelClass: AppAuthClient,
modelClass: OAuthClient,
join: {
from: 'app_configs.key',
to: 'app_auth_clients.app_key',
to: 'oauth_clients.app_key',
},
},
};

View File

@@ -2,7 +2,7 @@ import AES from 'crypto-js/aes.js';
import enc from 'crypto-js/enc-utf8.js';
import App from './app.js';
import AppConfig from './app-config.js';
import AppAuthClient from './app-auth-client.js';
import OAuthClient from './oauth-client.js';
import Base from './base.js';
import User from './user.js';
import Step from './step.js';
@@ -24,7 +24,7 @@ class Connection extends Base {
data: { type: 'string' },
formattedData: { type: 'object' },
userId: { type: 'string', format: 'uuid' },
appAuthClientId: { type: 'string', format: 'uuid' },
oauthClientId: { type: 'string', format: 'uuid' },
verified: { type: 'boolean', default: false },
draft: { type: 'boolean' },
deletedAt: { type: 'string' },
@@ -69,12 +69,12 @@ class Connection extends Base {
to: 'app_configs.key',
},
},
appAuthClient: {
oauthClient: {
relation: Base.BelongsToOneRelation,
modelClass: AppAuthClient,
modelClass: OAuthClient,
join: {
from: 'connections.app_auth_client_id',
to: 'app_auth_clients.id',
from: 'connections.oauth_client_id',
to: 'oauth_clients.id',
},
},
});
@@ -136,8 +136,8 @@ class Connection extends Base {
if (!this.formattedData) {
const authClient = await appConfig
.$relatedQuery('appAuthClients')
.findById(this.appAuthClientId)
.$relatedQuery('oauthClients')
.findById(this.oauthClientId)
.where({ active: true })
.throwIfNotFound();
@@ -215,13 +215,13 @@ class Connection extends Base {
return updatedConnection;
}
async updateFormattedData({ formattedData, appAuthClientId }) {
if (appAuthClientId) {
const appAuthClient = await AppAuthClient.query()
.findById(appAuthClientId)
async updateFormattedData({ formattedData, oauthClientId }) {
if (oauthClientId) {
const oauthClient = await OAuthClient.query()
.findById(oauthClientId)
.throwIfNotFound();
formattedData = appAuthClient.formattedAuthDefaults;
formattedData = oauthClient.formattedAuthDefaults;
}
return await this.$query().patchAndFetch({

View File

@@ -2,7 +2,7 @@ import { describe, it, expect, vi } from 'vitest';
import AES from 'crypto-js/aes.js';
import enc from 'crypto-js/enc-utf8.js';
import appConfig from '../config/app.js';
import AppAuthClient from './app-auth-client.js';
import OAuthClient from './oauth-client.js';
import App from './app.js';
import AppConfig from './app-config.js';
import Base from './base.js';
@@ -12,7 +12,7 @@ import User from './user.js';
import Telemetry from '../helpers/telemetry/index.js';
import { createConnection } from '../../test/factories/connection.js';
import { createAppConfig } from '../../test/factories/app-config.js';
import { createAppAuthClient } from '../../test/factories/app-auth-client.js';
import { createOAuthClient } from '../../test/factories/oauth-client.js';
describe('Connection model', () => {
it('tableName should return correct name', () => {
@@ -61,12 +61,12 @@ describe('Connection model', () => {
to: 'app_configs.key',
},
},
appAuthClient: {
oauthClient: {
relation: Base.BelongsToOneRelation,
modelClass: AppAuthClient,
modelClass: OAuthClient,
join: {
from: 'connections.app_auth_client_id',
to: 'app_auth_clients.id',
from: 'connections.oauth_client_id',
to: 'oauth_clients.id',
},
},
};
@@ -307,13 +307,13 @@ describe('Connection model', () => {
);
});
it('should apply app auth client auth defaults when creating with shared app auth client', async () => {
it('should apply oauth client auth defaults when creating with shared oauth client', async () => {
await createAppConfig({
key: 'gitlab',
disabled: false,
});
const appAuthClient = await createAppAuthClient({
const oauthClient = await createOAuthClient({
appKey: 'gitlab',
active: true,
formattedAuthDefaults: {
@@ -323,7 +323,7 @@ describe('Connection model', () => {
const connection = await createConnection({
key: 'gitlab',
appAuthClientId: appAuthClient.id,
oauthClientId: oauthClient.id,
formattedData: null,
});
@@ -559,22 +559,22 @@ describe('Connection model', () => {
});
describe('updateFormattedData', () => {
it('should extend connection data with app auth client auth defaults', async () => {
const appAuthClient = await createAppAuthClient({
it('should extend connection data with oauth client auth defaults', async () => {
const oauthClient = await createOAuthClient({
formattedAuthDefaults: {
clientId: 'sample-id',
},
});
const connection = await createConnection({
appAuthClientId: appAuthClient.id,
oauthClientId: oauthClient.id,
formattedData: {
token: 'sample-token',
},
});
const updatedConnection = await connection.updateFormattedData({
appAuthClientId: appAuthClient.id,
oauthClientId: oauthClient.id,
});
expect(updatedConnection.formattedData).toStrictEqual({

View File

@@ -4,8 +4,8 @@ import appConfig from '../config/app.js';
import Base from './base.js';
import AppConfig from './app-config.js';
class AppAuthClient extends Base {
static tableName = 'app_auth_clients';
class OAuthClient extends Base {
static tableName = 'oauth_clients';
static jsonSchema = {
type: 'object',
@@ -27,7 +27,7 @@ class AppAuthClient extends Base {
relation: Base.BelongsToOneRelation,
modelClass: AppConfig,
join: {
from: 'app_auth_clients.app_key',
from: 'oauth_clients.app_key',
to: 'app_configs.key',
},
},
@@ -87,4 +87,4 @@ class AppAuthClient extends Base {
}
}
export default AppAuthClient;
export default OAuthClient;

View File

@@ -0,0 +1,192 @@
import { describe, it, expect, vi } from 'vitest';
import AES from 'crypto-js/aes.js';
import enc from 'crypto-js/enc-utf8.js';
import AppConfig from './app-config.js';
import OAuthClient from './oauth-client.js';
import Base from './base.js';
import appConfig from '../config/app.js';
import { createOAuthClient } from '../../test/factories/oauth-client.js';
describe('OAuthClient model', () => {
it('tableName should return correct name', () => {
expect(OAuthClient.tableName).toBe('oauth_clients');
});
it('jsonSchema should have correct validations', () => {
expect(OAuthClient.jsonSchema).toMatchSnapshot();
});
it('relationMappings should return correct associations', () => {
const relationMappings = OAuthClient.relationMappings();
const expectedRelations = {
appConfig: {
relation: Base.BelongsToOneRelation,
modelClass: AppConfig,
join: {
from: 'oauth_clients.app_key',
to: 'app_configs.key',
},
},
};
expect(relationMappings).toStrictEqual(expectedRelations);
});
describe('encryptData', () => {
it('should return undefined if eligibleForEncryption is not true', async () => {
vi.spyOn(OAuthClient.prototype, 'eligibleForEncryption').mockReturnValue(
false
);
const oauthClient = new OAuthClient();
expect(oauthClient.encryptData()).toBeUndefined();
});
it('should encrypt formattedAuthDefaults and set it to authDefaults', async () => {
vi.spyOn(OAuthClient.prototype, 'eligibleForEncryption').mockReturnValue(
true
);
const formattedAuthDefaults = {
key: 'value',
};
const oauthClient = new OAuthClient();
oauthClient.formattedAuthDefaults = formattedAuthDefaults;
oauthClient.encryptData();
const expectedDecryptedValue = JSON.parse(
AES.decrypt(oauthClient.authDefaults, appConfig.encryptionKey).toString(
enc
)
);
expect(formattedAuthDefaults).toStrictEqual(expectedDecryptedValue);
expect(oauthClient.authDefaults).not.toStrictEqual(formattedAuthDefaults);
});
it('should encrypt formattedAuthDefaults and remove formattedAuthDefaults', async () => {
vi.spyOn(OAuthClient.prototype, 'eligibleForEncryption').mockReturnValue(
true
);
const formattedAuthDefaults = {
key: 'value',
};
const oauthClient = new OAuthClient();
oauthClient.formattedAuthDefaults = formattedAuthDefaults;
oauthClient.encryptData();
expect(oauthClient.formattedAuthDefaults).not.toBeDefined();
});
});
describe('decryptData', () => {
it('should return undefined if eligibleForDecryption is not true', () => {
vi.spyOn(OAuthClient.prototype, 'eligibleForDecryption').mockReturnValue(
false
);
const oauthClient = new OAuthClient();
expect(oauthClient.decryptData()).toBeUndefined();
});
it('should decrypt authDefaults and set it to formattedAuthDefaults', async () => {
vi.spyOn(OAuthClient.prototype, 'eligibleForDecryption').mockReturnValue(
true
);
const formattedAuthDefaults = {
key: 'value',
};
const authDefaults = AES.encrypt(
JSON.stringify(formattedAuthDefaults),
appConfig.encryptionKey
).toString();
const oauthClient = new OAuthClient();
oauthClient.authDefaults = authDefaults;
oauthClient.decryptData();
expect(oauthClient.formattedAuthDefaults).toStrictEqual(
formattedAuthDefaults
);
expect(oauthClient.authDefaults).not.toStrictEqual(formattedAuthDefaults);
});
});
describe('eligibleForEncryption', () => {
it('should return true when formattedAuthDefaults property exists', async () => {
const oauthClient = await createOAuthClient();
expect(oauthClient.eligibleForEncryption()).toBe(true);
});
it("should return false when formattedAuthDefaults property doesn't exist", async () => {
const oauthClient = await createOAuthClient();
delete oauthClient.formattedAuthDefaults;
expect(oauthClient.eligibleForEncryption()).toBe(false);
});
});
describe('eligibleForDecryption', () => {
it('should return true when authDefaults property exists', async () => {
const oauthClient = await createOAuthClient();
expect(oauthClient.eligibleForDecryption()).toBe(true);
});
it("should return false when authDefaults property doesn't exist", async () => {
const oauthClient = await createOAuthClient();
delete oauthClient.authDefaults;
expect(oauthClient.eligibleForDecryption()).toBe(false);
});
});
it('$beforeInsert should call OAuthClient.encryptData', async () => {
const oauthClientBeforeInsertSpy = vi.spyOn(
OAuthClient.prototype,
'encryptData'
);
await createOAuthClient();
expect(oauthClientBeforeInsertSpy).toHaveBeenCalledOnce();
});
it('$beforeUpdate should call OAuthClient.encryptData', async () => {
const oauthClient = await createOAuthClient();
const oauthClientBeforeUpdateSpy = vi.spyOn(
OAuthClient.prototype,
'encryptData'
);
await oauthClient.$query().patchAndFetch({ name: 'sample' });
expect(oauthClientBeforeUpdateSpy).toHaveBeenCalledOnce();
});
it('$afterFind should call OAuthClient.decryptData', async () => {
const oauthClient = await createOAuthClient();
const oauthClientAfterFindSpy = vi.spyOn(
OAuthClient.prototype,
'decryptData'
);
await oauthClient.$query();
expect(oauthClientAfterFindSpy).toHaveBeenCalledOnce();
});
});