mirror of
https://github.com/n8n-io/n8n.git
synced 2024-10-05 17:17:45 +03:00
reafactor(core): extract AuthUser into a separate entity
This commit is contained in:
parent
e07de837b9
commit
2c53a7e93c
@ -20,6 +20,7 @@ import { License } from '@/License';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { AuthProviderSyncHistoryRepository } from '@db/repositories/authProviderSyncHistory.repository';
|
||||
import { AuthIdentityRepository } from '@db/repositories/authIdentity.repository';
|
||||
import type { AuthUser } from '@/databases/entities/AuthUser';
|
||||
|
||||
/**
|
||||
* Check whether the LDAP feature is disabled in the instance
|
||||
@ -187,7 +188,7 @@ export const processUsers = async (
|
||||
user,
|
||||
transactionManager,
|
||||
);
|
||||
const authIdentity = AuthIdentity.create(savedUser, ldapId);
|
||||
const authIdentity = AuthIdentity.create(savedUser as AuthUser, ldapId);
|
||||
return await transactionManager.save(authIdentity);
|
||||
}),
|
||||
...toUpdateUsers.map(async ([ldapId, user]) => {
|
||||
@ -271,9 +272,12 @@ export const getMappingAttributes = (ldapConfig: LdapConfig): string[] => {
|
||||
};
|
||||
|
||||
export const createLdapAuthIdentity = async (user: User, ldapId: string) => {
|
||||
return await Container.get(AuthIdentityRepository).save(AuthIdentity.create(user, ldapId), {
|
||||
transaction: false,
|
||||
});
|
||||
return await Container.get(AuthIdentityRepository).save(
|
||||
AuthIdentity.create(user as AuthUser, ldapId),
|
||||
{
|
||||
transaction: false,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const createLdapUserOnLocalDb = async (data: Partial<User>, ldapId: string) => {
|
||||
|
@ -15,7 +15,7 @@ import config from '@/config';
|
||||
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { License } from '@/License';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { AuthUserRepository } from '@db/repositories/authUser.repository';
|
||||
import { UrlService } from '@/services/url.service';
|
||||
import type { AuthenticatedRequest } from '@/requests';
|
||||
|
||||
@ -94,7 +94,7 @@ async function createApiRouter(
|
||||
schema: OpenAPIV3.ApiKeySecurityScheme,
|
||||
): Promise<boolean> => {
|
||||
const apiKey = req.headers[schema.name.toLowerCase()] as string;
|
||||
const user = await Container.get(UserRepository).findOne({
|
||||
const user = await Container.get(AuthUserRepository).findOne({
|
||||
where: { apiKey },
|
||||
});
|
||||
|
||||
|
@ -5,8 +5,9 @@ import { JsonWebTokenError, TokenExpiredError } from 'jsonwebtoken';
|
||||
|
||||
import config from '@/config';
|
||||
import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES, Time } from '@/constants';
|
||||
import type { AuthUser } from '@db/entities/AuthUser';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { AuthUserRepository } from '@db/repositories/authUser.repository';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
|
||||
import { License } from '@/License';
|
||||
@ -55,7 +56,7 @@ export class AuthService {
|
||||
private readonly license: License,
|
||||
private readonly jwtService: JwtService,
|
||||
private readonly urlService: UrlService,
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly authUserRepository: AuthUserRepository,
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
this.authMiddleware = this.authMiddleware.bind(this);
|
||||
@ -115,13 +116,13 @@ export class AuthService {
|
||||
});
|
||||
}
|
||||
|
||||
async resolveJwt(token: string, req: AuthenticatedRequest, res: Response): Promise<User> {
|
||||
async resolveJwt(token: string, req: AuthenticatedRequest, res: Response): Promise<AuthUser> {
|
||||
const jwtPayload: IssuedJWT = this.jwtService.verify(token, {
|
||||
algorithms: ['HS256'],
|
||||
});
|
||||
|
||||
// TODO: Use an in-memory ttl-cache to cache the User object for upto a minute
|
||||
const user = await this.userRepository.findOne({
|
||||
const user = await this.authUserRepository.findOne({
|
||||
where: { id: jwtPayload.id },
|
||||
});
|
||||
|
||||
@ -171,7 +172,7 @@ export class AuthService {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
async resolvePasswordResetToken(token: string): Promise<User | undefined> {
|
||||
async resolvePasswordResetToken(token: string): Promise<AuthUser | undefined> {
|
||||
let decodedToken: PasswordResetToken;
|
||||
try {
|
||||
decodedToken = this.jwtService.verify(token);
|
||||
@ -184,7 +185,7 @@ export class AuthService {
|
||||
return;
|
||||
}
|
||||
|
||||
const user = await this.userRepository.findOne({
|
||||
const user = await this.authUserRepository.findOne({
|
||||
where: { id: decodedToken.sub },
|
||||
relations: ['authIdentities'],
|
||||
});
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Container } from 'typedi';
|
||||
import type { Response } from 'express';
|
||||
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { AuthUser } from '@db/entities/AuthUser';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
// This method is still used by cloud hooks.
|
||||
// DO NOT DELETE until the hooks have been updated
|
||||
/** @deprecated Use `AuthService` instead */
|
||||
export function issueCookie(res: Response, user: User) {
|
||||
export function issueCookie(res: Response, user: AuthUser) {
|
||||
return Container.get(AuthService).issueCookie(res, user);
|
||||
}
|
||||
|
@ -3,14 +3,14 @@ import { PasswordUtility } from '@/services/password.utility';
|
||||
import { Container } from 'typedi';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { isLdapLoginEnabled } from '@/Ldap/helpers';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { AuthUserRepository } from '@db/repositories/authUser.repository';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
|
||||
export const handleEmailLogin = async (
|
||||
email: string,
|
||||
password: string,
|
||||
): Promise<User | undefined> => {
|
||||
const user = await Container.get(UserRepository).findOne({
|
||||
const user = await Container.get(AuthUserRepository).findOne({
|
||||
where: { email },
|
||||
relations: ['authIdentities'],
|
||||
});
|
||||
|
@ -22,6 +22,7 @@ import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { AuthUserService } from '@/services/authUser.service';
|
||||
|
||||
@RestController('/me')
|
||||
export class MeController {
|
||||
@ -30,6 +31,7 @@ export class MeController {
|
||||
private readonly externalHooks: ExternalHooks,
|
||||
private readonly internalHooks: InternalHooks,
|
||||
private readonly authService: AuthService,
|
||||
private readonly authUserService: AuthUserService,
|
||||
private readonly userService: UserService,
|
||||
private readonly passwordUtility: PasswordUtility,
|
||||
private readonly userRepository: UserRepository,
|
||||
@ -189,7 +191,7 @@ export class MeController {
|
||||
async createAPIKey(req: AuthenticatedRequest) {
|
||||
const apiKey = `n8n_api_${randomBytes(40).toString('hex')}`;
|
||||
|
||||
await this.userService.update(req.user.id, { apiKey });
|
||||
await this.authUserService.update(req.user.id, { apiKey });
|
||||
|
||||
void this.internalHooks.onApiKeyCreated({
|
||||
user: req.user,
|
||||
@ -212,7 +214,7 @@ export class MeController {
|
||||
*/
|
||||
@Delete('/api-key')
|
||||
async deleteAPIKey(req: AuthenticatedRequest) {
|
||||
await this.userService.update(req.user.id, { apiKey: null });
|
||||
await this.authUserService.update(req.user.id, { apiKey: null });
|
||||
|
||||
void this.internalHooks.onApiKeyDeleted({
|
||||
user: req.user,
|
||||
|
@ -20,7 +20,7 @@ import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { UnprocessableRequestError } from '@/errors/response-errors/unprocessable.error';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { AuthUserRepository } from '@/databases/repositories/authUser.repository';
|
||||
|
||||
@RestController()
|
||||
export class PasswordResetController {
|
||||
@ -35,7 +35,7 @@ export class PasswordResetController {
|
||||
private readonly urlService: UrlService,
|
||||
private readonly license: License,
|
||||
private readonly passwordUtility: PasswordUtility,
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly authUserRepository: AuthUserRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@ -70,7 +70,7 @@ export class PasswordResetController {
|
||||
}
|
||||
|
||||
// User should just be able to reset password if one is already present
|
||||
const user = await this.userRepository.findNonShellUser(email);
|
||||
const user = await this.authUserRepository.findByEmail(email);
|
||||
|
||||
if (!user?.isOwner && !this.license.isWithinUsersLimit()) {
|
||||
this.logger.debug(
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Column, Entity, ManyToOne, PrimaryColumn, Unique } from '@n8n/typeorm';
|
||||
import { WithTimestamps } from './AbstractEntity';
|
||||
import { User } from './User';
|
||||
import { AuthUser } from './AuthUser';
|
||||
|
||||
export type AuthProviderType = 'ldap' | 'email' | 'saml'; // | 'google';
|
||||
|
||||
@ -10,8 +10,8 @@ export class AuthIdentity extends WithTimestamps {
|
||||
@Column()
|
||||
userId: string;
|
||||
|
||||
@ManyToOne(() => User, (user) => user.authIdentities)
|
||||
user: User;
|
||||
@ManyToOne(() => AuthUser, (user) => user.authIdentities)
|
||||
user: AuthUser;
|
||||
|
||||
@PrimaryColumn()
|
||||
providerId: string;
|
||||
@ -20,7 +20,7 @@ export class AuthIdentity extends WithTimestamps {
|
||||
providerType: AuthProviderType;
|
||||
|
||||
static create(
|
||||
user: User,
|
||||
user: AuthUser,
|
||||
providerId: string,
|
||||
providerType: AuthProviderType = 'ldap',
|
||||
): AuthIdentity {
|
||||
|
13
packages/cli/src/databases/entities/AuthUser.ts
Normal file
13
packages/cli/src/databases/entities/AuthUser.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Column, Entity, Index, OneToMany } from '@n8n/typeorm';
|
||||
import type { AuthIdentity } from './AuthIdentity';
|
||||
import { User } from './User';
|
||||
|
||||
@Entity({ name: 'user' })
|
||||
export class AuthUser extends User {
|
||||
@Column({ type: String, nullable: true })
|
||||
@Index({ unique: true })
|
||||
apiKey?: string | null;
|
||||
|
||||
@OneToMany('AuthIdentity', 'user')
|
||||
authIdentities: AuthIdentity[];
|
||||
}
|
@ -17,7 +17,6 @@ import { NoXss } from '../utils/customValidators';
|
||||
import { objectRetriever, lowerCaser } from '../utils/transformers';
|
||||
import { WithTimestamps, jsonColumnType } from './AbstractEntity';
|
||||
import type { IPersonalizationSurveyAnswers } from '@/Interfaces';
|
||||
import type { AuthIdentity } from './AuthIdentity';
|
||||
import {
|
||||
GLOBAL_OWNER_SCOPES,
|
||||
GLOBAL_MEMBER_SCOPES,
|
||||
@ -65,6 +64,7 @@ export class User extends WithTimestamps implements IUser {
|
||||
@IsString({ message: 'Password must be of type string.' })
|
||||
password: string;
|
||||
|
||||
// TODO: move to AuthUser
|
||||
@Column({
|
||||
type: jsonColumnType,
|
||||
nullable: true,
|
||||
@ -72,6 +72,7 @@ export class User extends WithTimestamps implements IUser {
|
||||
})
|
||||
personalizationAnswers: IPersonalizationSurveyAnswers | null;
|
||||
|
||||
// TODO: move to AuthUser
|
||||
@Column({
|
||||
type: jsonColumnType,
|
||||
nullable: true,
|
||||
@ -81,9 +82,6 @@ export class User extends WithTimestamps implements IUser {
|
||||
@Column()
|
||||
role: GlobalRole;
|
||||
|
||||
@OneToMany('AuthIdentity', 'user')
|
||||
authIdentities: AuthIdentity[];
|
||||
|
||||
@OneToMany('SharedWorkflow', 'user')
|
||||
sharedWorkflows: SharedWorkflow[];
|
||||
|
||||
@ -102,10 +100,6 @@ export class User extends WithTimestamps implements IUser {
|
||||
this.email = this.email?.toLowerCase() ?? null;
|
||||
}
|
||||
|
||||
@Column({ type: String, nullable: true })
|
||||
@Index({ unique: true })
|
||||
apiKey?: string | null;
|
||||
|
||||
@Column({ type: Boolean, default: false })
|
||||
mfaEnabled: boolean;
|
||||
|
||||
@ -152,7 +146,7 @@ export class User extends WithTimestamps implements IUser {
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
const { password, apiKey, mfaSecret, mfaRecoveryCodes, ...rest } = this;
|
||||
const { password, mfaSecret, mfaRecoveryCodes, ...rest } = this;
|
||||
return rest;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { AuthIdentity } from './AuthIdentity';
|
||||
import { AuthProviderSyncHistory } from './AuthProviderSyncHistory';
|
||||
import { AuthUser } from './AuthUser';
|
||||
import { CredentialsEntity } from './CredentialsEntity';
|
||||
import { EventDestinations } from './EventDestinations';
|
||||
import { ExecutionEntity } from './ExecutionEntity';
|
||||
@ -25,6 +26,7 @@ import { ProjectRelation } from './ProjectRelation';
|
||||
export const entities = {
|
||||
AuthIdentity,
|
||||
AuthProviderSyncHistory,
|
||||
AuthUser,
|
||||
CredentialsEntity,
|
||||
EventDestinations,
|
||||
ExecutionEntity,
|
||||
|
@ -0,0 +1,16 @@
|
||||
import { Service } from 'typedi';
|
||||
import { IsNull, Not, Repository } from '@n8n/typeorm';
|
||||
import type { AuthUser } from '../entities/AuthUser';
|
||||
|
||||
@Service()
|
||||
export class AuthUserRepository extends Repository<AuthUser> {
|
||||
async findByEmail(email: string) {
|
||||
return await this.findOne({
|
||||
where: {
|
||||
email,
|
||||
password: Not(IsNull()),
|
||||
},
|
||||
relations: ['authIdentities'],
|
||||
});
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import type { ListQuery } from '@/requests';
|
||||
import { type GlobalRole, User } from '../entities/User';
|
||||
import { Project } from '../entities/Project';
|
||||
import { ProjectRelation } from '../entities/ProjectRelation';
|
||||
|
||||
@Service()
|
||||
export class UserRepository extends Repository<User> {
|
||||
constructor(dataSource: DataSource) {
|
||||
|
@ -15,6 +15,7 @@ import { Expose } from 'class-transformer';
|
||||
import { IsBoolean, IsEmail, IsIn, IsOptional, IsString, Length } from 'class-validator';
|
||||
import { NoXss } from '@db/utils/customValidators';
|
||||
import type { PublicUser, SecretsProvider, SecretsProviderState } from '@/Interfaces';
|
||||
import type { AuthUser } from '@db/entities/AuthUser';
|
||||
import { AssignableRole } from '@db/entities/User';
|
||||
import type { GlobalRole, User } from '@db/entities/User';
|
||||
import type { Variables } from '@db/entities/Variables';
|
||||
@ -22,7 +23,7 @@ import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import type { WorkflowHistory } from '@db/entities/WorkflowHistory';
|
||||
import type { Project, ProjectType } from '@db/entities/Project';
|
||||
import type { ProjectRole } from './databases/entities/ProjectRelation';
|
||||
import type { ProjectRole } from '@db/entities/ProjectRelation';
|
||||
import type { Scope } from '@n8n/permissions';
|
||||
|
||||
export class UserUpdatePayload implements Pick<User, 'email' | 'firstName' | 'lastName'> {
|
||||
@ -85,7 +86,7 @@ export type AuthenticatedRequest<
|
||||
RequestBody = {},
|
||||
RequestQuery = {},
|
||||
> = Omit<APIRequest<RouteParams, ResponseBody, RequestBody, RequestQuery>, 'user' | 'cookies'> & {
|
||||
user: User;
|
||||
user: AuthUser;
|
||||
cookies: Record<string, string | undefined>;
|
||||
};
|
||||
|
||||
|
18
packages/cli/src/services/authUser.service.ts
Normal file
18
packages/cli/src/services/authUser.service.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Service } from 'typedi';
|
||||
import type { AuthUser } from '@db/entities/AuthUser';
|
||||
import { AuthUserRepository } from '@db/repositories/authUser.repository';
|
||||
|
||||
@Service()
|
||||
export class AuthUserService {
|
||||
constructor(private readonly authUserRepository: AuthUserRepository) {}
|
||||
|
||||
async update(userId: string, data: Partial<AuthUser>) {
|
||||
const user = await this.authUserRepository.findOneBy({ id: userId });
|
||||
|
||||
if (user) {
|
||||
await this.authUserRepository.save({ ...user, ...data }, { transaction: true });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
@ -57,14 +57,14 @@ export class UserService {
|
||||
withScopes?: boolean;
|
||||
},
|
||||
) {
|
||||
const { password, updatedAt, apiKey, authIdentities, mfaRecoveryCodes, mfaSecret, ...rest } =
|
||||
user;
|
||||
const { password, updatedAt, mfaRecoveryCodes, mfaSecret, ...rest } = user;
|
||||
|
||||
const ldapIdentity = authIdentities?.find((i) => i.providerType === 'ldap');
|
||||
// const ldapIdentity = authIdentities?.find((i) => i.providerType === 'ldap');
|
||||
|
||||
let publicUser: PublicUser = {
|
||||
...rest,
|
||||
signInType: ldapIdentity ? 'ldap' : 'email',
|
||||
// signInType: ldapIdentity ? 'ldap' : 'email',
|
||||
signInType: 'email',
|
||||
hasRecoveryCodesLeft: !!user.mfaRecoveryCodes?.length,
|
||||
};
|
||||
|
||||
|
@ -25,7 +25,7 @@ import https from 'https';
|
||||
import type { SamlLoginBinding } from './types';
|
||||
import { validateMetadata, validateResponse } from './samlValidator';
|
||||
import { Logger } from '@/Logger';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { AuthUserRepository } from '@db/repositories/authUser.repository';
|
||||
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
@ -172,7 +172,7 @@ export class SamlService {
|
||||
const attributes = await this.getAttributesFromLoginResponse(req, binding);
|
||||
if (attributes.email) {
|
||||
const lowerCasedEmail = attributes.email.toLowerCase();
|
||||
const user = await Container.get(UserRepository).findOne({
|
||||
const user = await Container.get(AuthUserRepository).findOne({
|
||||
where: { email: lowerCasedEmail },
|
||||
relations: ['authIdentities'],
|
||||
});
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { Container } from 'typedi';
|
||||
import config from '@/config';
|
||||
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
||||
import type { AuthUser } from '@db/entities/AuthUser';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { AuthIdentityRepository } from '@db/repositories/authIdentity.repository';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { License } from '@/License';
|
||||
import { PasswordUtility } from '@/services/password.utility';
|
||||
@ -17,8 +20,6 @@ import {
|
||||
} from '../ssoHelpers';
|
||||
import { getServiceProviderConfigTestReturnUrl } from './serviceProvider.ee';
|
||||
import type { SamlConfiguration } from './types/requests';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { AuthIdentityRepository } from '@db/repositories/authIdentity.repository';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
|
||||
@ -123,7 +124,7 @@ export async function createUserFromSamlAttributes(attributes: SamlUserAttribute
|
||||
}
|
||||
|
||||
export async function updateUserFromSamlAttributes(
|
||||
user: User,
|
||||
user: AuthUser,
|
||||
attributes: SamlUserAttributes,
|
||||
): Promise<User> {
|
||||
if (!attributes.email) throw new AuthError('Email is required to update user');
|
||||
|
@ -126,7 +126,7 @@ describe('InvitationController', () => {
|
||||
role: 'global:member',
|
||||
});
|
||||
|
||||
const invalidPaylods = [
|
||||
const invalidPayloads = [
|
||||
{
|
||||
firstName: randomName(),
|
||||
lastName: randomName(),
|
||||
@ -155,7 +155,7 @@ describe('InvitationController', () => {
|
||||
},
|
||||
];
|
||||
|
||||
for (const payload of invalidPaylods) {
|
||||
for (const payload of invalidPayloads) {
|
||||
await testServer.authlessAgent
|
||||
.post(`/invitations/${memberShell.id}/accept`)
|
||||
.send(payload)
|
||||
|
@ -1,4 +1,6 @@
|
||||
import Container from 'typedi';
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
import type TestAgent from 'supertest/lib/agent';
|
||||
import { IsNull } from '@n8n/typeorm';
|
||||
import validator from 'validator';
|
||||
import type { User } from '@db/entities/User';
|
||||
@ -13,10 +15,11 @@ import {
|
||||
import * as testDb from './shared/testDb';
|
||||
import * as utils from './shared/utils/';
|
||||
import { addApiKey, createUser, createUserShell } from './shared/db/users';
|
||||
import Container from 'typedi';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { ProjectRepository } from '@/databases/repositories/project.repository';
|
||||
|
||||
jest.setTimeout(1000);
|
||||
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['me'] });
|
||||
|
||||
beforeEach(async () => {
|
||||
@ -25,7 +28,7 @@ beforeEach(async () => {
|
||||
|
||||
describe('Owner shell', () => {
|
||||
let ownerShell: User;
|
||||
let authOwnerShellAgent: SuperAgentTest;
|
||||
let authOwnerShellAgent: TestAgent;
|
||||
|
||||
beforeEach(async () => {
|
||||
ownerShell = await createUserShell('global:owner');
|
||||
|
@ -1,9 +1,10 @@
|
||||
import type { Application } from 'express';
|
||||
import type { ICredentialDataDecryptedObject } from 'n8n-workflow';
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
import type TestAgent from 'supertest/lib/agent';
|
||||
import type { Server } from 'http';
|
||||
|
||||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import type { AuthUser } from '@/databases/entities/AuthUser';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { BooleanLicenseFeature, ICredentialsDb, NumericLicenseFeature } from '@/Interfaces';
|
||||
import type { LicenseMocker } from './license';
|
||||
@ -47,9 +48,9 @@ export interface SetupProps {
|
||||
export interface TestServer {
|
||||
app: Application;
|
||||
httpServer: Server;
|
||||
authAgentFor: (user: User) => SuperAgentTest;
|
||||
publicApiAgentFor: (user: User) => SuperAgentTest;
|
||||
authlessAgent: SuperAgentTest;
|
||||
authAgentFor: (user: AuthUser) => TestAgent;
|
||||
publicApiAgentFor: (user: AuthUser) => TestAgent;
|
||||
authlessAgent: TestAgent;
|
||||
license: LicenseMocker;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import { URL } from 'url';
|
||||
|
||||
import config from '@/config';
|
||||
import { AUTH_COOKIE_NAME } from '@/constants';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { AuthUser } from '@/databases/entities/AuthUser';
|
||||
import { registerController } from '@/decorators';
|
||||
import { rawBodyReader, bodyParser } from '@/middlewares';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
@ -45,7 +45,7 @@ function prefix(pathSegment: string) {
|
||||
}
|
||||
|
||||
const browserId = 'test-browser-id';
|
||||
function createAgent(app: express.Application, options?: { auth: boolean; user: User }) {
|
||||
function createAgent(app: express.Application, options?: { auth: boolean; user: AuthUser }) {
|
||||
const agent = request.agent(app);
|
||||
void agent.use(prefix(REST_PATH_SEGMENT));
|
||||
if (options?.auth && options?.user) {
|
||||
@ -57,7 +57,7 @@ function createAgent(app: express.Application, options?: { auth: boolean; user:
|
||||
|
||||
function publicApiAgent(
|
||||
app: express.Application,
|
||||
{ user, version = 1 }: { user: User; version?: number },
|
||||
{ user, version = 1 }: { user: AuthUser; version?: number },
|
||||
) {
|
||||
const agent = request.agent(app);
|
||||
void agent.use(prefix(`${PUBLIC_API_REST_PATH_SEGMENT}/v${version}`));
|
||||
@ -89,7 +89,7 @@ export const setupTestServer = ({
|
||||
const testServer: TestServer = {
|
||||
app,
|
||||
httpServer: app.listen(0),
|
||||
authAgentFor: (user: User) => createAgent(app, { auth: true, user }),
|
||||
authAgentFor: (user) => createAgent(app, { auth: true, user }),
|
||||
authlessAgent: createAgent(app),
|
||||
publicApiAgentFor: (user) => publicApiAgent(app, { user }),
|
||||
license: new LicenseMocker(),
|
||||
|
Loading…
Reference in New Issue
Block a user