Skip to content

Commit

Permalink
chore: expose types so we can use them properly (#5251)
Browse files Browse the repository at this point in the history
Expose types to be used in enterprise and cloud addons
  • Loading branch information
gastonfournier authored Nov 3, 2023
1 parent ddb9b5c commit 9688955
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 37 deletions.
24 changes: 13 additions & 11 deletions src/lib/middleware/api-token-middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });

Expand All @@ -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 });

Expand All @@ -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 });

Expand Down Expand Up @@ -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 });

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 });

Expand All @@ -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 });

Expand Down
13 changes: 7 additions & 6 deletions src/lib/middleware/api-token-middleware.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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');
Expand All @@ -42,15 +42,17 @@ const apiAccessMiddleware = (
return (req, res, next) => next();
}

return (req: IAuthRequest, res, next) => {
return (req: IAuthRequest | IApiRequest, res, next) => {
if (req.user) {
return next();
}

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) {
Expand Down Expand Up @@ -79,7 +81,6 @@ const apiAccessMiddleware = (
} catch (error) {
logger.warn(error);
}

next();
};
};
Expand Down
6 changes: 3 additions & 3 deletions src/lib/proxy/proxy-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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[];

Expand All @@ -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;
Expand Down
16 changes: 14 additions & 2 deletions src/lib/routes/unleash-types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import { Request } from 'express';
import User from '../types/user';
import IUser from '../types/user';
import { IApiUser } from '../types';

export interface IAuthRequest<
PARAM = any,
ResBody = any,
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;
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib/services/api-token-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -121,7 +121,7 @@ export class ApiTokenService {
}
}

public getUserForToken(secret: string): ApiUser | undefined {
public getUserForToken(secret: string): IApiUser | undefined {
if (!secret) {
return undefined;
}
Expand All @@ -138,7 +138,7 @@ export class ApiTokenService {
token = this.activeTokens.find(
(activeToken) =>
Boolean(activeToken.alias) &&
constantTimeCompare(activeToken.alias, secret),
constantTimeCompare(activeToken.alias!, secret),
);
}

Expand Down
18 changes: 15 additions & 3 deletions src/lib/types/api-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ValidationError } from 'joi';

import { CLIENT } from './permissions';

interface IApiUserData {
export interface IApiUserData {
permissions?: string[];
projects?: string[];
project?: string;
Expand All @@ -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[];
Expand All @@ -26,6 +35,8 @@ export default class ApiUser {

readonly secret: string;

readonly username: string;

constructor({
permissions = [CLIENT],
projects,
Expand All @@ -38,14 +49,15 @@ 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;
this.secret = secret;
if (projects && projects.length > 0) {
this.projects = projects;
} else {
this.projects = [project];
this.projects = project ? [project] : [];
}
}
}
16 changes: 8 additions & 8 deletions src/lib/types/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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';

Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Expand Down

0 comments on commit 9688955

Please sign in to comment.