mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-11 00:08:30 +01:00
chore: expose types so we can use them properly (#5251)
Expose types to be used in enterprise and cloud addons
This commit is contained in:
parent
ddb9b5c20f
commit
9688955d4b
@ -6,22 +6,24 @@ import { ALL, ApiTokenType } from '../types/models/api-token';
|
||||
import apiTokenMiddleware, {
|
||||
TOKEN_TYPE_ERROR_MESSAGE,
|
||||
} from './api-token-middleware';
|
||||
import { ApiTokenService } from 'lib/services';
|
||||
import { IUnleashConfig } from 'lib/types';
|
||||
|
||||
let config: any;
|
||||
let config: IUnleashConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
config = {
|
||||
config = createTestConfig({
|
||||
getLogger,
|
||||
authentication: {
|
||||
enableApiToken: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
test('should not do anything if request does not contain a authorization', async () => {
|
||||
const apiTokenService = {
|
||||
getUserForToken: jest.fn(),
|
||||
};
|
||||
} as unknown as ApiTokenService;
|
||||
|
||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||
|
||||
@ -40,7 +42,7 @@ test('should not do anything if request does not contain a authorization', async
|
||||
test('should not add user if unknown token', async () => {
|
||||
const apiTokenService = {
|
||||
getUserForToken: jest.fn(),
|
||||
};
|
||||
} as unknown as ApiTokenService;
|
||||
|
||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||
|
||||
@ -61,7 +63,7 @@ test('should not add user if unknown token', async () => {
|
||||
test('should not make database query when provided PAT format', async () => {
|
||||
const apiTokenService = {
|
||||
getUserForToken: jest.fn(),
|
||||
};
|
||||
} as unknown as ApiTokenService;
|
||||
|
||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||
|
||||
@ -91,7 +93,7 @@ test('should add user if known token', async () => {
|
||||
});
|
||||
const apiTokenService = {
|
||||
getUserForToken: jest.fn().mockReturnValue(apiUser),
|
||||
};
|
||||
} as unknown as ApiTokenService;
|
||||
|
||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||
|
||||
@ -124,7 +126,7 @@ test('should not add user if not /api/client', async () => {
|
||||
|
||||
const apiTokenService = {
|
||||
getUserForToken: jest.fn().mockReturnValue(apiUser),
|
||||
};
|
||||
} as unknown as ApiTokenService;
|
||||
|
||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||
const cb = jest.fn();
|
||||
@ -162,7 +164,7 @@ test('should not add user if disabled', async () => {
|
||||
});
|
||||
const apiTokenService = {
|
||||
getUserForToken: jest.fn().mockReturnValue(apiUser),
|
||||
};
|
||||
} as unknown as ApiTokenService;
|
||||
|
||||
const disabledConfig = createTestConfig({
|
||||
getLogger,
|
||||
@ -203,7 +205,7 @@ test('should call next if apiTokenService throws', async () => {
|
||||
getUserForToken: () => {
|
||||
throw new Error('hi there, i am stupid');
|
||||
},
|
||||
};
|
||||
} as unknown as ApiTokenService;
|
||||
|
||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||
|
||||
@ -226,7 +228,7 @@ test('should call next if apiTokenService throws x2', async () => {
|
||||
getUserForToken: () => {
|
||||
throw new Error('hi there, i am stupid');
|
||||
},
|
||||
};
|
||||
} as unknown as ApiTokenService;
|
||||
|
||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { ApiTokenType } from '../types/models/api-token';
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import { IAuthRequest } from '../routes/unleash-types';
|
||||
import { IApiRequest, IAuthRequest } from '../routes/unleash-types';
|
||||
import { IUnleashServices } from 'lib/server-impl';
|
||||
|
||||
const isClientApi = ({ path }) => {
|
||||
return path && path.indexOf('/api/client') > -1;
|
||||
@ -33,7 +33,7 @@ const apiAccessMiddleware = (
|
||||
authentication,
|
||||
flagResolver,
|
||||
}: Pick<IUnleashConfig, 'getLogger' | 'authentication' | 'flagResolver'>,
|
||||
{ apiTokenService }: any,
|
||||
{ apiTokenService }: Pick<IUnleashServices, 'apiTokenService'>,
|
||||
): any => {
|
||||
const logger = getLogger('/middleware/api-token.ts');
|
||||
logger.debug('Enabling api-token middleware');
|
||||
@ -42,7 +42,7 @@ const apiAccessMiddleware = (
|
||||
return (req, res, next) => next();
|
||||
}
|
||||
|
||||
return (req: IAuthRequest, res, next) => {
|
||||
return (req: IAuthRequest | IApiRequest, res, next) => {
|
||||
if (req.user) {
|
||||
return next();
|
||||
}
|
||||
@ -50,7 +50,9 @@ const apiAccessMiddleware = (
|
||||
try {
|
||||
const apiToken = req.header('authorization');
|
||||
if (!apiToken?.startsWith('user:')) {
|
||||
const apiUser = apiTokenService.getUserForToken(apiToken);
|
||||
const apiUser = apiToken
|
||||
? apiTokenService.getUserForToken(apiToken)
|
||||
: undefined;
|
||||
const { CLIENT, FRONTEND } = ApiTokenType;
|
||||
|
||||
if (apiUser) {
|
||||
@ -79,7 +81,6 @@ const apiAccessMiddleware = (
|
||||
} catch (error) {
|
||||
logger.warn(error);
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
@ -2,7 +2,7 @@ import EventEmitter from 'events';
|
||||
import { RepositoryInterface } from 'unleash-client/lib/repository';
|
||||
import { Segment } from 'unleash-client/lib/strategy/strategy';
|
||||
import { FeatureInterface } from 'unleash-client/lib/feature';
|
||||
import ApiUser from '../types/api-user';
|
||||
import { IApiUser } from '../types/api-user';
|
||||
import { IUnleashConfig, IUnleashServices, IUnleashStores } from '../types';
|
||||
import {
|
||||
mapFeaturesForClient,
|
||||
@ -35,7 +35,7 @@ export class ProxyRepository extends EventEmitter implements RepositoryInterface
|
||||
|
||||
private readonly configurationRevisionService: ConfigurationRevisionService;
|
||||
|
||||
private readonly token: ApiUser;
|
||||
private readonly token: IApiUser;
|
||||
|
||||
private features: FeatureInterface[];
|
||||
|
||||
@ -51,7 +51,7 @@ export class ProxyRepository extends EventEmitter implements RepositoryInterface
|
||||
config: Config,
|
||||
stores: Stores,
|
||||
services: Services,
|
||||
token: ApiUser,
|
||||
token: IApiUser,
|
||||
) {
|
||||
super();
|
||||
this.config = config;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Request } from 'express';
|
||||
import User from '../types/user';
|
||||
import IUser from '../types/user';
|
||||
import { IApiUser } from '../types';
|
||||
|
||||
export interface IAuthRequest<
|
||||
PARAM = any,
|
||||
@ -7,7 +8,18 @@ export interface IAuthRequest<
|
||||
ReqBody = any,
|
||||
ReqQuery = any,
|
||||
> extends Request<PARAM, ResBody, ReqBody, ReqQuery> {
|
||||
user: User;
|
||||
user: IUser;
|
||||
logout: (() => void) | ((callback: (err?: any) => void) => void);
|
||||
session: any;
|
||||
}
|
||||
|
||||
export interface IApiRequest<
|
||||
PARAM = any,
|
||||
ResBody = any,
|
||||
ReqBody = any,
|
||||
ReqQuery = any,
|
||||
> extends Request<PARAM, ResBody, ReqBody, ReqQuery> {
|
||||
user: IApiUser;
|
||||
logout: (() => void) | ((callback: (err?: any) => void) => void);
|
||||
session: any;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { Logger } from '../logger';
|
||||
import { ADMIN, CLIENT, FRONTEND } from '../types/permissions';
|
||||
import { IUnleashStores } from '../types/stores';
|
||||
import { IUnleashConfig } from '../types/option';
|
||||
import ApiUser from '../types/api-user';
|
||||
import ApiUser, { IApiUser } from '../types/api-user';
|
||||
import {
|
||||
ApiTokenType,
|
||||
IApiToken,
|
||||
@ -121,7 +121,7 @@ export class ApiTokenService {
|
||||
}
|
||||
}
|
||||
|
||||
public getUserForToken(secret: string): ApiUser | undefined {
|
||||
public getUserForToken(secret: string): IApiUser | undefined {
|
||||
if (!secret) {
|
||||
return undefined;
|
||||
}
|
||||
@ -138,7 +138,7 @@ export class ApiTokenService {
|
||||
token = this.activeTokens.find(
|
||||
(activeToken) =>
|
||||
Boolean(activeToken.alias) &&
|
||||
constantTimeCompare(activeToken.alias, secret),
|
||||
constantTimeCompare(activeToken.alias!, secret),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { ValidationError } from 'joi';
|
||||
|
||||
import { CLIENT } from './permissions';
|
||||
|
||||
interface IApiUserData {
|
||||
export interface IApiUserData {
|
||||
permissions?: string[];
|
||||
projects?: string[];
|
||||
project?: string;
|
||||
@ -13,7 +13,16 @@ interface IApiUserData {
|
||||
tokenName: string;
|
||||
}
|
||||
|
||||
export default class ApiUser {
|
||||
export interface IApiUser {
|
||||
username: string;
|
||||
permissions: string[];
|
||||
projects: string[];
|
||||
environment: string;
|
||||
type: ApiTokenType;
|
||||
secret: string;
|
||||
}
|
||||
|
||||
export default class ApiUser implements IApiUser {
|
||||
readonly isAPI: boolean = true;
|
||||
|
||||
readonly permissions: string[];
|
||||
@ -26,6 +35,8 @@ export default class ApiUser {
|
||||
|
||||
readonly secret: string;
|
||||
|
||||
readonly username: string;
|
||||
|
||||
constructor({
|
||||
permissions = [CLIENT],
|
||||
projects,
|
||||
@ -38,6 +49,7 @@ export default class ApiUser {
|
||||
if (!tokenName) {
|
||||
throw new ValidationError('tokenName is required', [], undefined);
|
||||
}
|
||||
this.username = tokenName;
|
||||
this.permissions = permissions;
|
||||
this.environment = environment;
|
||||
this.type = type;
|
||||
@ -45,7 +57,7 @@ export default class ApiUser {
|
||||
if (projects && projects.length > 0) {
|
||||
this.projects = projects;
|
||||
} else {
|
||||
this.projects = [project];
|
||||
this.projects = project ? [project] : [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ export interface IUser {
|
||||
email?: string;
|
||||
inviteLink?: string;
|
||||
seenAt?: Date;
|
||||
createdAt: Date;
|
||||
createdAt?: Date;
|
||||
permissions: string[];
|
||||
loginAttempts: number;
|
||||
loginAttempts?: number;
|
||||
isAPI: boolean;
|
||||
imageUrl: string;
|
||||
accountType?: AccountType;
|
||||
@ -50,11 +50,11 @@ export default class User implements IUser {
|
||||
|
||||
imageUrl: string;
|
||||
|
||||
seenAt: Date;
|
||||
seenAt?: Date;
|
||||
|
||||
loginAttempts: number;
|
||||
loginAttempts?: number;
|
||||
|
||||
createdAt: Date;
|
||||
createdAt?: Date;
|
||||
|
||||
accountType?: AccountType = 'User';
|
||||
|
||||
@ -77,9 +77,9 @@ export default class User implements IUser {
|
||||
Joi.assert(name, Joi.string(), 'Name');
|
||||
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.name = name!;
|
||||
this.username = username!;
|
||||
this.email = email!;
|
||||
this.imageUrl = imageUrl || this.generateImageUrl();
|
||||
this.seenAt = seenAt;
|
||||
this.loginAttempts = loginAttempts;
|
||||
|
@ -29,7 +29,7 @@ afterAll(async () => {
|
||||
await db.destroy();
|
||||
});
|
||||
|
||||
test('Access to//api/admin/tags are refused no matter how many leading slashes', async () => {
|
||||
test('Access to //api/admin/tags are refused no matter how many leading slashes', async () => {
|
||||
await app.request.get('//api/admin/tags').expect(401);
|
||||
await app.request.get('////api/admin/tags').expect(401);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user