Skip to content
New issue

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

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

Already on GitHub? # to your account

fix(core): Return unredacted credentials from GET credentials/:id #12447

Merged
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 packages/cli/src/credentials/credentials.service.ee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class EnterpriseCredentialsService {
if (credential) {
// Decrypt the data if we found the credential with the `credential:update`
// scope.
decryptedData = this.credentialsService.decrypt(credential);
decryptedData = this.credentialsService.decrypt(credential, true);
} else {
// Otherwise try to find them with only the `credential:read` scope. In
// that case we return them without the decrypted data.
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/credentials/credentials.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ export class CredentialsService {
if (sharing) {
// Decrypt the data if we found the credential with the `credential:update`
// scope.
decryptedData = this.decrypt(sharing.credentials);
decryptedData = this.decrypt(sharing.credentials, true);
} else {
// Otherwise try to find them with only the `credential:read` scope. In
// that case we return them without the decrypted data.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { In } from '@n8n/typeorm';
import { Container } from 'typedi';

import config from '@/config';
import { CredentialsService } from '@/credentials/credentials.service';
import type { Project } from '@/databases/entities/project';
import type { ProjectRole } from '@/databases/entities/project-relation';
import type { User } from '@/databases/entities/user';
Expand Down Expand Up @@ -555,6 +556,22 @@ describe('GET /credentials/:id', () => {
expect(secondCredential.data).toBeDefined();
});

test('should not redact the data when `includeData:true` is passed', async () => {
const credentialService = Container.get(CredentialsService);
const redactSpy = jest.spyOn(credentialService, 'redact');
const savedCredential = await saveCredential(randomCredentialPayload(), {
user: owner,
});

const response = await authOwnerAgent
.get(`/credentials/${savedCredential.id}`)
.query({ includeData: true });

validateMainCredentialData(response.body.data);
expect(response.body.data.data).toBeDefined();
expect(redactSpy).not.toHaveBeenCalled();
});

test('should retrieve non-owned cred for owner', async () => {
const [member1, member2] = await createManyUsers(2, {
role: 'global:member',
Expand Down
18 changes: 18 additions & 0 deletions packages/cli/test/integration/credentials/credentials.api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Credentials } from 'n8n-core';
import { randomString } from 'n8n-workflow';
import { Container } from 'typedi';

import { CredentialsService } from '@/credentials/credentials.service';
import type { Project } from '@/databases/entities/project';
import type { User } from '@/databases/entities/user';
import { CredentialsRepository } from '@/databases/repositories/credentials.repository';
Expand Down Expand Up @@ -1272,6 +1273,23 @@ describe('GET /credentials/:id', () => {
expect(secondResponse.body.data.data).toBeDefined();
});

test('should not redact the data when `includeData:true` is passed', async () => {
const credentialService = Container.get(CredentialsService);
const redactSpy = jest.spyOn(credentialService, 'redact');
const savedCredential = await saveCredential(randomCredentialPayload(), {
user: owner,
role: 'credential:owner',
});

const response = await authOwnerAgent
.get(`/credentials/${savedCredential.id}`)
.query({ includeData: true });

validateMainCredentialData(response.body.data);
expect(response.body.data.data).toBeDefined();
expect(redactSpy).not.toHaveBeenCalled();
});

test('should retrieve owned cred for member', async () => {
const savedCredential = await saveCredential(randomCredentialPayload(), {
user: member,
Expand Down
Loading