diff --git a/src/modules/api/admin/admin.service.ts b/src/modules/api/admin/admin.service.ts index 9520671..7f9a76d 100644 --- a/src/modules/api/admin/admin.service.ts +++ b/src/modules/api/admin/admin.service.ts @@ -1,24 +1,11 @@ import { Injectable } from '@nestjs/common'; import { Client } from 'connect-redis'; -import { OAuth2Client } from 'src/modules/objects/oauth2-client/oauth2-client.entity'; import { User } from 'src/modules/objects/user/user.entity'; -import { FormUtilityService } from 'src/modules/utility/services/form-utility.service'; const UNPRIVILEGED_STRIP = ['openid', 'id_token', 'management', 'implicit']; @Injectable() export class AdminService { - constructor(private _form: FormUtilityService) {} - - public stripClientInfo(client: OAuth2Client): Partial { - return { - ...client, - owner: client.owner - ? this._form.pluckObject(client.owner, ['id', 'uuid', 'username']) - : null, - } as Partial; - } - public userHasPrivilege(user: User, privilege: string): boolean { return user.privileges.some(({ name }) => name === privilege); } diff --git a/src/modules/api/admin/oauth2-admin.controller.ts b/src/modules/api/admin/oauth2-admin.controller.ts index c9d7c8a..19f4421 100644 --- a/src/modules/api/admin/oauth2-admin.controller.ts +++ b/src/modules/api/admin/oauth2-admin.controller.ts @@ -109,7 +109,11 @@ export class OAuth2AdminController { user, RELATIONS, ); - return unprivileged.map((item) => this._service.stripClientInfo(item)); + + return { + pagination: null, + list: unprivileged.map((item) => this._oaClient.stripClientInfo(item)), + }; } const search = options.q ? decodeURIComponent(options.q) : null; @@ -130,7 +134,7 @@ export class OAuth2AdminController { return { pagination, list: this._form.stripObjectArray( - list.map((item) => this._service.stripClientInfo(item)), + list.map((item) => this._oaClient.stripClientInfo(item)), ['password'], ), }; @@ -151,7 +155,7 @@ export class OAuth2AdminController { ); } - return this._service.stripClientInfo(client); + return this._oaClient.stripClientInfo(client); } @Patch('clients/:id') @@ -182,13 +186,13 @@ export class OAuth2AdminController { } if (!Object.keys(allowedFieldsOnly).length) { - return this._service.stripClientInfo(client); + return this._oaClient.stripClientInfo(client); } Object.assign(client, allowedFieldsOnly); await this._oaClient.updateClient(client); - return this._service.stripClientInfo(client); + return this._oaClient.stripClientInfo(client); } @Post('clients/:id/new-secret') @@ -213,7 +217,7 @@ export class OAuth2AdminController { await this._oaToken.wipeClientTokens(client); await this._oaClient.wipeClientAuthorizations(client); - return this._service.stripClientInfo(client); + return this._oaClient.stripClientInfo(client); } @Delete('clients/:id/authorizations') @@ -236,7 +240,7 @@ export class OAuth2AdminController { await this._oaClient.wipeClientAuthorizations(client); - return this._service.stripClientInfo(client); + return this._oaClient.stripClientInfo(client); } @Get('clients/:id/urls') @@ -435,7 +439,7 @@ export class OAuth2AdminController { client.picture = null; await this._oaClient.updateClient(client); - return this._service.stripClientInfo(client); + return this._oaClient.stripClientInfo(client); } // New client @@ -487,6 +491,6 @@ export class OAuth2AdminController { client.owner = user; await this._oaClient.updateClient(client); - return this._service.stripClientInfo(client); + return this._oaClient.stripClientInfo(client); } } diff --git a/src/modules/api/api.controller.ts b/src/modules/api/api.controller.ts index 6201ddc..71aa14f 100644 --- a/src/modules/api/api.controller.ts +++ b/src/modules/api/api.controller.ts @@ -1,15 +1,80 @@ +import { OAuth2AccessToken } from '@icynet/oauth2-provider'; import { Controller, Get, UseGuards } from '@nestjs/common'; +import { Bearer } from 'src/decorators/bearer.decorator'; +import { Scope } from 'src/decorators/scope.decorator'; import { CurrentUser } from 'src/decorators/user.decorator'; import { OAuth2Guard } from 'src/guards/oauth2.guard'; +import { ScopesGuard } from 'src/guards/scopes.guard'; +import { ConfigurationService } from '../config/config.service'; +import { OAuth2ClientService } from '../objects/oauth2-client/oauth2-client.service'; import { User } from '../objects/user/user.entity'; +import { FormUtilityService } from '../utility/services/form-utility.service'; @Controller({ path: '/api', }) export class ApiController { - @Get('/') + constructor( + private _config: ConfigurationService, + private _oaClient: OAuth2ClientService, + private _form: FormUtilityService, + ) {} + + @Get('/user') @UseGuards(OAuth2Guard) - index(@CurrentUser() user: User) { - return { hello: true, user: user.username }; + getCurrentUser(@CurrentUser() user: User, @Scope() scopeStr: string) { + const scope = scopeStr.split(' '); + // Management scope allows access to basically everything anyway + const scopelessAccess = scope.includes('management'); + + const userData: Record = { + id: user.id, + uuid: user.uuid, + username: user.username, + display_name: user.display_name, + + // Standard claims + name: user.display_name, + preferred_username: user.username, + nickname: user.display_name, + }; + + if (scope.includes('email') || scopelessAccess) { + userData.email = user.email; + userData.email_verified = true; + } + + if ((scope.includes('image') || scopelessAccess) && user.picture) { + userData.image = `${this._config.get('app.base_url')}/uploads/${ + user.picture.file + }`; + userData.image_file = user.picture.file; + } + + if ( + (scope.includes('privileges') || scopelessAccess) && + user.privileges?.length + ) { + userData.privileges = user.privileges.map(({ name }) => name); + } + + return userData; + } + + @Get('/client') + @UseGuards(OAuth2Guard, ScopesGuard) + async getCurrentClient(@Bearer() token: OAuth2AccessToken) { + const client = await this._oaClient.getById(token.client_id, [ + 'urls', + 'picture', + ]); + return this._form.pluckObject(client, [ + 'title', + 'description', + 'client_id', + 'urls', + 'picture', + 'verified', + ]); } } diff --git a/src/modules/objects/oauth2-client/oauth2-client.service.ts b/src/modules/objects/oauth2-client/oauth2-client.service.ts index 87989ad..d324946 100644 --- a/src/modules/objects/oauth2-client/oauth2-client.service.ts +++ b/src/modules/objects/oauth2-client/oauth2-client.service.ts @@ -1,4 +1,5 @@ import { Inject, Injectable } from '@nestjs/common'; +import { FormUtilityService } from 'src/modules/utility/services/form-utility.service'; import { ILike, Repository } from 'typeorm'; import { Upload } from '../upload/upload.entity'; import { UploadService } from '../upload/upload.service'; @@ -29,6 +30,7 @@ export class OAuth2ClientService { @Inject('CLIENT_AUTHORIZATION_REPOSITORY') private clientAuthRepository: Repository, private _upload: UploadService, + private _form: FormUtilityService, ) {} public async hasAuthorized( @@ -270,4 +272,21 @@ export class OAuth2ClientService { await this._upload.delete(client.picture); } } + + public stripClientInfo(client: OAuth2Client): Partial { + return { + ...client, + owner: client.owner + ? this._form.pluckObject(client.owner, ['id', 'uuid', 'username']) + : null, + picture: client.picture + ? this._form.pluckObject(client.picture, [ + 'id', + 'mimetype', + 'file', + 'created_at', + ]) + : null, + } as Partial; + } }