Skip to content

Commit

Permalink
Add validateKey function to ApiKeysService
Browse files Browse the repository at this point in the history
  • Loading branch information
MrBartusek committed Apr 25, 2024
1 parent 5409c06 commit 6e15370
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
1 change: 1 addition & 0 deletions apps/api/src/api-keys/api-keys.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ import { ApiKeysService } from './api-keys.service';
controllers: [ApiKeysController],
providers: [ApiKeysService],
imports: [UsersModule],
exports: [ApiKeysService],
})
export class ApiKeysModule {}
43 changes: 43 additions & 0 deletions apps/api/src/api-keys/api-keys.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing';
import { Types } from 'mongoose';
import { UserRepository } from '../models/users/users.repository';
import { ApiKeysService } from './api-keys.service';
import { profile } from 'node:console';

Check warning on line 5 in apps/api/src/api-keys/api-keys.service.spec.ts

View workflow job for this annotation

GitHub Actions / Lint

'profile' is defined but never used

describe('ApiKeysService', () => {
let service: ApiKeysService;
Expand Down Expand Up @@ -76,4 +77,46 @@ describe('ApiKeysService', () => {
const [user] = dto.apiKey.split('.');
expect(user).toEqual(userId.toString());
});

describe('Validate key', () => {
it('should get user on valid key', async () => {
const userId = new Types.ObjectId();
mockUserRepository.findById.mockResolvedValue({
profile: {
username: 'test',
},
auth: {
password: 'password',
apiKey: `${userId}.current-key`,
},
});

const user = await service.validateKey(`${userId}.current-key`);
expect(user.username).toBe('test');
});

it('should not get user on invalid key', async () => {
const userId = new Types.ObjectId();
mockUserRepository.findById.mockResolvedValue({
profile: {
username: 'test',
},
auth: {
password: 'password',
apiKey: `${userId}.current-key`,
},
});

const user = await service.validateKey(`${userId}.invalid-key`);
expect(user).toBeNull();
});

it('should not get invalid user', async () => {
mockUserRepository.findById.mockResolvedValue(null);

const user = await service.validateKey(`${new Types.ObjectId()}.key`);

expect(user).toBeNull();
});
});
});
14 changes: 14 additions & 0 deletions apps/api/src/api-keys/api-keys.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
import { Types } from 'mongoose';
import * as crypto from 'node:crypto';
import { ApiKeyDto } from 'shared-types';
import { UserProfile } from '../models/users/schemas/user-profile.schema';
import { UserRepository } from '../models/users/users.repository';

@Injectable()
Expand Down Expand Up @@ -30,6 +31,19 @@ export class ApiKeysService {
return { user: userId.toString(), apiKey };
}

async validateKey(input: string): Promise<UserProfile | null> {
const [userIdString] = input.split('.');
if (!userIdString) return null;
const userId = new Types.ObjectId(userIdString);

const user = await this.userRepository.findById(userId);
if (!user) return null;

const apiKey = user.auth.apiKey;
const keyValid = apiKey == input;
return keyValid ? user.profile : null;
}

private generateApiKey(userId: Types.ObjectId): string {
const randomHash = crypto.randomBytes(32).toString('hex');
return `${userId}.${randomHash}`;
Expand Down

0 comments on commit 6e15370

Please sign in to comment.