Skip to content
This repository has been archived by the owner on Apr 19, 2023. It is now read-only.

Commit

Permalink
♻️ Add group/user methods in API kes
Browse files Browse the repository at this point in the history
  • Loading branch information
AnandChowdhary committed Nov 8, 2020
1 parent 245e645 commit 89af802
Show file tree
Hide file tree
Showing 2 changed files with 188 additions and 14 deletions.
14 changes: 7 additions & 7 deletions src/modules/api-keys/api-keys.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class ApiKeyController {
@Param('groupId', ParseIntPipe) groupId: number,
@Body() data: CreateApiKeyDto,
): Promise<Expose<apiKeys>> {
return this.apiKeysService.createApiKey(groupId, data);
return this.apiKeysService.createApiKeyForGroup(groupId, data);
}

@Get()
Expand All @@ -49,7 +49,7 @@ export class ApiKeyController {
@Query('where', WherePipe) where?: Record<string, number | string>,
@Query('orderBy', OrderByPipe) orderBy?: Record<string, 'asc' | 'desc'>,
): Promise<Expose<apiKeys>[]> {
return this.apiKeysService.getApiKeys(groupId, {
return this.apiKeysService.getApiKeysForGroup(groupId, {
skip,
take,
orderBy,
Expand All @@ -63,7 +63,7 @@ export class ApiKeyController {
async scopes(
@Param('groupId', ParseIntPipe) groupId: number,
): Promise<Record<string, string>> {
return this.apiKeysService.getApiKeyScopes(groupId);
return this.apiKeysService.getApiKeyScopesForGroup(groupId);
}

@Get(':id')
Expand All @@ -72,7 +72,7 @@ export class ApiKeyController {
@Param('groupId', ParseIntPipe) groupId: number,
@Param('id', ParseIntPipe) id: number,
): Promise<Expose<apiKeys>> {
return this.apiKeysService.getApiKey(groupId, Number(id));
return this.apiKeysService.getApiKeyForGroup(groupId, Number(id));
}

@Patch(':id')
Expand All @@ -83,7 +83,7 @@ export class ApiKeyController {
@Param('groupId', ParseIntPipe) groupId: number,
@Param('id', ParseIntPipe) id: number,
): Promise<Expose<apiKeys>> {
return this.apiKeysService.updateApiKey(groupId, Number(id), data);
return this.apiKeysService.updateApiKeyForGroup(groupId, Number(id), data);
}

@Put(':id')
Expand All @@ -94,7 +94,7 @@ export class ApiKeyController {
@Param('groupId', ParseIntPipe) groupId: number,
@Param('id', ParseIntPipe) id: number,
): Promise<Expose<apiKeys>> {
return this.apiKeysService.updateApiKey(groupId, Number(id), data);
return this.apiKeysService.updateApiKeyForGroup(groupId, Number(id), data);
}

@Delete(':id')
Expand All @@ -104,6 +104,6 @@ export class ApiKeyController {
@Param('groupId', ParseIntPipe) groupId: number,
@Param('id', ParseIntPipe) id: number,
): Promise<Expose<apiKeys>> {
return this.apiKeysService.deleteApiKey(groupId, Number(id));
return this.apiKeysService.deleteApiKeyForGroup(groupId, Number(id));
}
}
188 changes: 181 additions & 7 deletions src/modules/api-keys/api-keys.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class ApiKeysService {
private configService: ConfigService,
) {}

async createApiKey(
async createApiKeyForGroup(
groupId: number,
data: Omit<Omit<apiKeysCreateInput, 'apiKey'>, 'group'>,
): Promise<apiKeys> {
Expand All @@ -41,8 +41,17 @@ export class ApiKeysService {
data: { ...data, apiKey, group: { connect: { id: groupId } } },
});
}
async createApiKeyForUser(
userId: number,
data: Omit<Omit<apiKeysCreateInput, 'apiKey'>, 'user'>,
): Promise<apiKeys> {
const apiKey = this.tokensService.generateUuid();
return this.prisma.apiKeys.create({
data: { ...data, apiKey, user: { connect: { id: userId } } },
});
}

async getApiKeys(
async getApiKeysForGroup(
groupId: number,
params: {
skip?: number;
Expand All @@ -62,8 +71,31 @@ export class ApiKeysService {
});
return apiKeys.map((group) => this.prisma.expose<apiKeys>(group));
}
async getApiKeysForUser(
userId: number,
params: {
skip?: number;
take?: number;
cursor?: apiKeysWhereUniqueInput;
where?: apiKeysWhereInput;
orderBy?: apiKeysOrderByInput;
},
): Promise<Expose<apiKeys>[]> {
const { skip, take, cursor, where, orderBy } = params;
const apiKeys = await this.prisma.apiKeys.findMany({
skip,
take,
cursor,
where: { ...where, user: { id: userId } },
orderBy,
});
return apiKeys.map((user) => this.prisma.expose<apiKeys>(user));
}

async getApiKey(groupId: number, id: number): Promise<Expose<apiKeys>> {
async getApiKeyForGroup(
groupId: number,
id: number,
): Promise<Expose<apiKeys>> {
const apiKey = await this.prisma.apiKeys.findOne({
where: { id },
});
Expand All @@ -72,6 +104,15 @@ export class ApiKeysService {
if (apiKey.groupId !== groupId) throw new UnauthorizedException();
return this.prisma.expose<apiKeys>(apiKey);
}
async getApiKeyForUser(userId: number, id: number): Promise<Expose<apiKeys>> {
const apiKey = await this.prisma.apiKeys.findOne({
where: { id },
});
if (!apiKey)
throw new HttpException('ApiKey not found', HttpStatus.NOT_FOUND);
if (apiKey.userId !== userId) throw new UnauthorizedException();
return this.prisma.expose<apiKeys>(apiKey);
}

async getApiKeyFromKey(key: string): Promise<Expose<apiKeys>> {
const apiKey = await this.prisma.apiKeys.findFirst({
Expand All @@ -84,7 +125,7 @@ export class ApiKeysService {
return this.prisma.expose<apiKeys>(apiKey);
}

async updateApiKey(
async updateApiKeyForGroup(
groupId: number,
id: number,
data: apiKeysUpdateInput,
Expand All @@ -102,8 +143,26 @@ export class ApiKeysService {
this.lru.delete(testApiKey.apiKey);
return this.prisma.expose<apiKeys>(apiKey);
}
async updateApiKeyForUser(
userId: number,
id: number,
data: apiKeysUpdateInput,
): Promise<Expose<apiKeys>> {
const testApiKey = await this.prisma.apiKeys.findOne({
where: { id },
});
if (!testApiKey)
throw new HttpException('ApiKey not found', HttpStatus.NOT_FOUND);
if (testApiKey.userId !== userId) throw new UnauthorizedException();
const apiKey = await this.prisma.apiKeys.update({
where: { id },
data,
});
this.lru.delete(testApiKey.apiKey);
return this.prisma.expose<apiKeys>(apiKey);
}

async replaceApiKey(
async replaceApiKeyForGroup(
groupId: number,
id: number,
data: apiKeysCreateInput,
Expand All @@ -121,8 +180,29 @@ export class ApiKeysService {
this.lru.delete(testApiKey.apiKey);
return this.prisma.expose<apiKeys>(apiKey);
}
async replaceApiKeyForUser(
userId: number,
id: number,
data: apiKeysCreateInput,
): Promise<Expose<apiKeys>> {
const testApiKey = await this.prisma.apiKeys.findOne({
where: { id },
});
if (!testApiKey)
throw new HttpException('ApiKey not found', HttpStatus.NOT_FOUND);
if (testApiKey.userId !== userId) throw new UnauthorizedException();
const apiKey = await this.prisma.apiKeys.update({
where: { id },
data,
});
this.lru.delete(testApiKey.apiKey);
return this.prisma.expose<apiKeys>(apiKey);
}

async deleteApiKey(groupId: number, id: number): Promise<Expose<apiKeys>> {
async deleteApiKeyForGroup(
groupId: number,
id: number,
): Promise<Expose<apiKeys>> {
const testApiKey = await this.prisma.apiKeys.findOne({
where: { id },
});
Expand All @@ -135,8 +215,26 @@ export class ApiKeysService {
this.lru.delete(testApiKey.apiKey);
return this.prisma.expose<apiKeys>(apiKey);
}
async deleteApiKeyForUser(
userId: number,
id: number,
): Promise<Expose<apiKeys>> {
const testApiKey = await this.prisma.apiKeys.findOne({
where: { id },
});
if (!testApiKey)
throw new HttpException('ApiKey not found', HttpStatus.NOT_FOUND);
if (testApiKey.userId !== userId) throw new UnauthorizedException();
const apiKey = await this.prisma.apiKeys.delete({
where: { id },
});
this.lru.delete(testApiKey.apiKey);
return this.prisma.expose<apiKeys>(apiKey);
}

async getApiKeyScopes(groupId: number): Promise<Record<string, string>> {
async getApiKeyScopesForGroup(
groupId: number,
): Promise<Record<string, string>> {
const scopes: Record<string, string> = {};
scopes[`group-${groupId}:read-info`] = 'Read group details';
scopes[`group-${groupId}:write-info`] = 'Update group details';
Expand Down Expand Up @@ -224,4 +322,80 @@ export class ApiKeysService {
scopes[`group-${groupId}:read-audit-log-*`] = 'Read audit logs';
return scopes;
}

async getApiKeyScopesForUser(
userId: number,
): Promise<Record<string, string>> {
const scopes: Record<string, string> = {};
scopes[`user-${userId}:read-info`] = 'Read user details';
scopes[`user-${userId}:write-info`] = 'Update user details';
scopes[`user-${userId}:delete`] = 'Delete user';

scopes[`user-${userId}:write-membership-*`] = 'Create new groups';
scopes[`user-${userId}:read-membership-*`] = 'Read group memberships';
for await (const membership of await this.prisma.memberships.findMany({
where: { user: { id: userId } },
select: { id: true, group: true },
})) {
scopes[
`user-${userId}:read-membership-${membership.id}`
] = `Read membership: ${membership.group.name}`;
scopes[
`user-${userId}:write-membership-${membership.id}`
] = `Update membership: ${membership.group.name}`;
scopes[
`user-${userId}:delete-membership-${membership.id}`
] = `Delete membership: ${membership.group.name}`;
}

scopes[`user-${userId}:write-email-*`] = 'Create and update emails';
scopes[`user-${userId}:read-email-*`] = 'Read emails';
for await (const email of await this.prisma.emails.findMany({
where: { user: { id: userId } },
select: { id: true, email: true },
})) {
scopes[
`user-${userId}:read-email-${email.id}`
] = `Read email: ${email.email}`;
scopes[
`user-${userId}:delete-email-${email.id}`
] = `Delete email: ${email.email}`;
}

scopes[`user-${userId}:read-session-*`] = 'Read sessions';
for await (const session of await this.prisma.sessions.findMany({
where: { user: { id: userId } },
select: { id: true, browser: true },
})) {
scopes[`user-${userId}:read-session-${session.id}`] = `Read session: ${
session.browser ?? session.id
}`;
scopes[
`user-${userId}:delete-session-${session.id}`
] = `Delete session: ${session.browser ?? session.id}`;
}

scopes[`user-${userId}:read-approved-subnet-*`] = 'Read approvedSubnets';
for await (const subnet of await this.prisma.approvedSubnets.findMany({
where: { user: { id: userId } },
select: { id: true, subnet: true },
})) {
scopes[
`user-${userId}:read-approved-subnet-${subnet.id}`
] = `Read subnet: ${subnet.subnet}`;
scopes[
`user-${userId}:delete-approved-subnet-${subnet.id}`
] = `Delete subnet: ${subnet.subnet}`;
}

scopes[`user-${userId}:delete-mfa-*`] =
'Disable multi-factor authentication';
scopes[`user-${userId}:write-mfa-regenerate`] =
'Regenerate MFA backup codes';
scopes[`user-${userId}:write-mfa-totp`] = 'Enable TOTP-based MFA';
scopes[`user-${userId}:write-mfa-sms`] = 'Enable SMS-based MFA';
scopes[`user-${userId}:write-mfa-email`] = 'Enable email-based MFA';

return scopes;
}
}

0 comments on commit 89af802

Please sign in to comment.