icynet-auth-server/src/modules/api/api.controller.ts

127 lines
3.5 KiB
TypeScript

import { OAuth2AccessToken } from '@icynet/oauth2-provider';
import {
Controller,
Get,
NotFoundException,
Param,
StreamableFile,
UseGuards,
} from '@nestjs/common';
import { join } from 'path';
import { createReadStream } from 'fs';
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';
import { UploadService } from '../objects/upload/upload.service';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
@ApiTags('api')
@Controller({
path: '/api',
})
export class ApiController {
constructor(
private _config: ConfigurationService,
private _oaClient: OAuth2ClientService,
private _form: FormUtilityService,
private _upload: UploadService,
) {}
@Get()
welcome() {
return {
welcome: { to: 'Icy Network!' },
api: true,
oauth2: {
authorizationUrl: '/oauth2/authorize',
tokenUrl: '/oauth2/token',
userUrl: '/api/user',
},
swaggerdoc: '/api/openapi',
};
}
@Get('/user')
@ApiBearerAuth()
@UseGuards(OAuth2Guard)
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<string, unknown> = {
id: user.id,
uuid: user.uuid,
username: user.username,
display_name: user.display_name,
// Standard claims
sub: user.uuid,
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('picture') || scopelessAccess) && user.picture) {
userData.picture = `${this._config.get('app.base_url')}/uploads/${
user.picture.file
}`;
userData.picture_file = user.picture.file;
}
if (
(scope.includes('privileges') || scopelessAccess) &&
user.privileges?.length
) {
userData.privileges = user.privileges.map(({ name }) => name);
}
return userData;
}
@Get('/client')
@ApiBearerAuth()
@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',
]);
}
@Get('/upload/:file')
@ApiBearerAuth()
@UseGuards(OAuth2Guard)
async sendFile(@Param('file') fileName: string) {
const cleanFile = decodeURI(fileName).replace(/(\&(.*))/, '');
const file = await this._upload.getByFile(cleanFile);
if (!file) {
throw new NotFoundException('File not found');
}
const path = join(this._upload.uploadPath, file.file);
const stream = createReadStream(path);
return new StreamableFile(stream);
}
}