fix some middleware nonsense
This commit is contained in:
parent
564f3427a4
commit
b02191608a
@ -44,6 +44,7 @@ async function bootstrap() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
|
/\/((?!api).)*/,
|
||||||
session({
|
session({
|
||||||
secret: process.env.SESSION_SECRET,
|
secret: process.env.SESSION_SECRET,
|
||||||
resave: true,
|
resave: true,
|
||||||
|
@ -48,6 +48,7 @@ const SET_CLIENT_FIELDS = [
|
|||||||
'grants',
|
'grants',
|
||||||
'activated',
|
'activated',
|
||||||
'verified',
|
'verified',
|
||||||
|
'urls',
|
||||||
];
|
];
|
||||||
|
|
||||||
const URL_TYPES = ['redirect_uri', 'terms', 'privacy', 'website'];
|
const URL_TYPES = ['redirect_uri', 'terms', 'privacy', 'website'];
|
||||||
@ -167,6 +168,10 @@ export class OAuth2AdminController {
|
|||||||
@CurrentUser() user: User,
|
@CurrentUser() user: User,
|
||||||
) {
|
) {
|
||||||
const client = await this._oaClient.getById(parseInt(id, 10), []);
|
const client = await this._oaClient.getById(parseInt(id, 10), []);
|
||||||
|
const reducedPermissions = !this._service.userHasPrivilege(
|
||||||
|
user,
|
||||||
|
'admin:oauth2',
|
||||||
|
);
|
||||||
if (!client) {
|
if (!client) {
|
||||||
throw new NotFoundException('Client not found');
|
throw new NotFoundException('Client not found');
|
||||||
}
|
}
|
||||||
@ -178,9 +183,11 @@ export class OAuth2AdminController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const allowedFieldsOnly = this._form.pluckObject(setter, SET_CLIENT_FIELDS);
|
const allowedFieldsOnly = this._form.pluckObject(setter, SET_CLIENT_FIELDS);
|
||||||
|
const urls = allowedFieldsOnly.urls?.slice();
|
||||||
|
delete allowedFieldsOnly.urls;
|
||||||
|
|
||||||
// Non-admin cannot change the activated or verified status
|
// Non-admin cannot change the activated or verified status
|
||||||
if (!this._service.userHasPrivilege(user, 'admin:oauth2')) {
|
if (reducedPermissions) {
|
||||||
delete allowedFieldsOnly.activated;
|
delete allowedFieldsOnly.activated;
|
||||||
delete allowedFieldsOnly.verified;
|
delete allowedFieldsOnly.verified;
|
||||||
}
|
}
|
||||||
@ -189,9 +196,33 @@ export class OAuth2AdminController {
|
|||||||
return this._oaClient.stripClientInfo(client);
|
return this._oaClient.stripClientInfo(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const splitGrants = allowedFieldsOnly.grants.split(' ');
|
||||||
|
const splitScopes = allowedFieldsOnly.scope.split(' ');
|
||||||
|
let availableGrantTypes = this._oaClient.availableGrantTypes;
|
||||||
|
let availableScopes = this._oaClient.availableScopes;
|
||||||
|
|
||||||
|
if (reducedPermissions) {
|
||||||
|
availableGrantTypes =
|
||||||
|
this._service.removeUnprivileged(availableGrantTypes);
|
||||||
|
availableScopes = this._service.removeUnprivileged(availableScopes);
|
||||||
|
allowedFieldsOnly.activated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!splitGrants.every((grant) => availableGrantTypes.includes(grant))) {
|
||||||
|
throw new BadRequestException('Bad grant types');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!splitScopes.every((scope) => availableScopes.includes(scope))) {
|
||||||
|
throw new BadRequestException('Bad scopes');
|
||||||
|
}
|
||||||
|
|
||||||
Object.assign(client, allowedFieldsOnly);
|
Object.assign(client, allowedFieldsOnly);
|
||||||
await this._oaClient.updateClient(client);
|
await this._oaClient.updateClient(client);
|
||||||
|
|
||||||
|
if (urls?.length) {
|
||||||
|
await this._oaClient.upsertURLs(client, urls);
|
||||||
|
}
|
||||||
|
|
||||||
return this._oaClient.stripClientInfo(client);
|
return this._oaClient.stripClientInfo(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,6 +515,9 @@ export class OAuth2AdminController {
|
|||||||
throw new BadRequestException('Bad scopes');
|
throw new BadRequestException('Bad scopes');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const urls = setter.urls?.slice();
|
||||||
|
delete allowedFieldsOnly.urls;
|
||||||
|
|
||||||
const client = new OAuth2Client();
|
const client = new OAuth2Client();
|
||||||
Object.assign(client, allowedFieldsOnly);
|
Object.assign(client, allowedFieldsOnly);
|
||||||
client.client_id = this._token.createUUID();
|
client.client_id = this._token.createUUID();
|
||||||
@ -491,6 +525,10 @@ export class OAuth2AdminController {
|
|||||||
client.owner = user;
|
client.owner = user;
|
||||||
await this._oaClient.updateClient(client);
|
await this._oaClient.updateClient(client);
|
||||||
|
|
||||||
|
if (urls?.length) {
|
||||||
|
await this._oaClient.upsertURLs(client, urls);
|
||||||
|
}
|
||||||
|
|
||||||
return this._oaClient.stripClientInfo(client);
|
return this._oaClient.stripClientInfo(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
Get,
|
Get,
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
Param,
|
Param,
|
||||||
|
Patch,
|
||||||
Post,
|
Post,
|
||||||
Put,
|
Put,
|
||||||
Query,
|
Query,
|
||||||
@ -18,6 +19,7 @@ import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
|||||||
import { PrivilegesGuard } from 'src/guards/privileges.guard';
|
import { PrivilegesGuard } from 'src/guards/privileges.guard';
|
||||||
import { ScopesGuard } from 'src/guards/scopes.guard';
|
import { ScopesGuard } from 'src/guards/scopes.guard';
|
||||||
import { PrivilegeService } from 'src/modules/objects/privilege/privilege.service';
|
import { PrivilegeService } from 'src/modules/objects/privilege/privilege.service';
|
||||||
|
import { User } from 'src/modules/objects/user/user.entity';
|
||||||
import { UserService } from 'src/modules/objects/user/user.service';
|
import { UserService } from 'src/modules/objects/user/user.service';
|
||||||
import { FormUtilityService } from 'src/modules/utility/services/form-utility.service';
|
import { FormUtilityService } from 'src/modules/utility/services/form-utility.service';
|
||||||
import { PaginationService } from 'src/modules/utility/services/paginate.service';
|
import { PaginationService } from 'src/modules/utility/services/paginate.service';
|
||||||
@ -80,6 +82,32 @@ export class UserAdminController {
|
|||||||
return this._form.stripObject(user, ['password']);
|
return this._form.stripObject(user, ['password']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Patch(':id')
|
||||||
|
@Scopes('management')
|
||||||
|
@Privileges('admin', 'admin:user')
|
||||||
|
async updateUser(@Param('id') id: string, @Body() body: Partial<User>) {
|
||||||
|
const user = await this._user.getById(parseInt(id, 10));
|
||||||
|
if (!user) {
|
||||||
|
throw new NotFoundException('User not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const allowedFieldsOnly = this._form.pluckObject(body, [
|
||||||
|
'display_name',
|
||||||
|
'username',
|
||||||
|
'email',
|
||||||
|
'activated',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!Object.keys(allowedFieldsOnly).length) {
|
||||||
|
throw new BadRequestException('No data was updated.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(user, allowedFieldsOnly);
|
||||||
|
await this._user.updateUser(user);
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a user avatar from the server
|
* Delete a user avatar from the server
|
||||||
* @param id User ID
|
* @param id User ID
|
||||||
@ -162,7 +190,7 @@ export class UserAdminController {
|
|||||||
* @param id User ID
|
* @param id User ID
|
||||||
* @returns Success or error
|
* @returns Success or error
|
||||||
*/
|
*/
|
||||||
@Post(':id/activate')
|
@Post(':id/activation')
|
||||||
@Scopes('management')
|
@Scopes('management')
|
||||||
@Privileges('admin', 'admin:user')
|
@Privileges('admin', 'admin:user')
|
||||||
async activateUserEmail(@Param('id') id: string) {
|
async activateUserEmail(@Param('id') id: string) {
|
||||||
|
@ -69,9 +69,9 @@ export class OAuth2Service {
|
|||||||
public clientService: OAuth2ClientService,
|
public clientService: OAuth2ClientService,
|
||||||
public tokenService: OAuth2TokenService,
|
public tokenService: OAuth2TokenService,
|
||||||
) {
|
) {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
// if (process.env.NODE_ENV === 'development') {
|
||||||
this.oauth.logger.setLogLevel('debug');
|
// this.oauth.logger.setLogLevel('debug');
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public splitScope(scope: string | string[]): string[] {
|
public splitScope(scope: string | string[]): string[] {
|
||||||
|
@ -168,6 +168,7 @@ export class OAuth2ClientService {
|
|||||||
: undefined,
|
: undefined,
|
||||||
skip: offset,
|
skip: offset,
|
||||||
take: limit,
|
take: limit,
|
||||||
|
order: { id: 'asc' },
|
||||||
relations,
|
relations,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -197,6 +198,7 @@ export class OAuth2ClientService {
|
|||||||
): Promise<OAuth2Client[]> {
|
): Promise<OAuth2Client[]> {
|
||||||
return this.clientRepository.find({
|
return this.clientRepository.find({
|
||||||
where: { owner: { id: owner.id } },
|
where: { owner: { id: owner.id } },
|
||||||
|
order: { id: 'asc' },
|
||||||
relations,
|
relations,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -234,6 +236,37 @@ export class OAuth2ClientService {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async upsertURLs(
|
||||||
|
client: OAuth2Client,
|
||||||
|
urls: OAuth2ClientURL[],
|
||||||
|
): Promise<OAuth2Client> {
|
||||||
|
const existingURLs = await this.getClientURLs(client.client_id);
|
||||||
|
const removed = [];
|
||||||
|
|
||||||
|
for (const existing of existingURLs) {
|
||||||
|
const alsoProvided = urls.find(({ id }) => id === existing.id);
|
||||||
|
if (alsoProvided && !!alsoProvided.url) {
|
||||||
|
Object.assign(existing, alsoProvided);
|
||||||
|
await this.updateClientURL(existing);
|
||||||
|
} else {
|
||||||
|
await this.deleteClientURL(existing);
|
||||||
|
removed.push(existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const newUrl of urls.filter((url) => !url.id)) {
|
||||||
|
const newUrlObject = this.reobjectifyURL(newUrl, client);
|
||||||
|
await this.updateClientURL(newUrlObject);
|
||||||
|
existingURLs.push(newUrlObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
client.urls = existingURLs
|
||||||
|
.filter(({ id }) => !removed.some((removed) => removed.id === id))
|
||||||
|
.map((itm) => ({ ...itm, client: undefined }));
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
public async updateClient(client: OAuth2Client): Promise<OAuth2Client> {
|
public async updateClient(client: OAuth2Client): Promise<OAuth2Client> {
|
||||||
await this.clientRepository.save(client);
|
await this.clientRepository.save(client);
|
||||||
return client;
|
return client;
|
||||||
@ -289,4 +322,14 @@ export class OAuth2ClientService {
|
|||||||
: null,
|
: null,
|
||||||
} as Partial<OAuth2Client>;
|
} as Partial<OAuth2Client>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private reobjectifyURL(
|
||||||
|
input: Partial<OAuth2ClientURL>,
|
||||||
|
client: OAuth2Client,
|
||||||
|
): OAuth2ClientURL {
|
||||||
|
const reObjectifyURL = new OAuth2ClientURL();
|
||||||
|
Object.assign(reObjectifyURL, input);
|
||||||
|
reObjectifyURL.client = client;
|
||||||
|
return reObjectifyURL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@ import {
|
|||||||
NestModule,
|
NestModule,
|
||||||
RequestMethod,
|
RequestMethod,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
||||||
|
import { UserMiddleware } from 'src/middleware/user.middleware';
|
||||||
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
||||||
import { UserTokenModule } from 'src/modules/objects/user-token/user-token.module';
|
import { UserTokenModule } from 'src/modules/objects/user-token/user-token.module';
|
||||||
import { UserModule } from 'src/modules/objects/user/user.module';
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
@ -16,6 +18,7 @@ import { LoginController } from './login.controller';
|
|||||||
})
|
})
|
||||||
export class LoginModule implements NestModule {
|
export class LoginModule implements NestModule {
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer.apply(CSRFMiddleware, UserMiddleware).forRoutes(LoginController);
|
||||||
consumer
|
consumer
|
||||||
.apply(ValidateCSRFMiddleware)
|
.apply(ValidateCSRFMiddleware)
|
||||||
.forRoutes({ path: 'login*', method: RequestMethod.POST });
|
.forRoutes({ path: 'login*', method: RequestMethod.POST });
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
||||||
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
|
import { UserMiddleware } from 'src/middleware/user.middleware';
|
||||||
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
||||||
import { OAuth2Module } from 'src/modules/oauth2/oauth2.module';
|
import { OAuth2Module } from 'src/modules/oauth2/oauth2.module';
|
||||||
import { OAuth2Service } from 'src/modules/oauth2/oauth2.service';
|
import { OAuth2Service } from 'src/modules/oauth2/oauth2.service';
|
||||||
@ -14,6 +16,7 @@ export class OAuth2RouterModule implements NestModule {
|
|||||||
constructor(private _service: OAuth2Service) {}
|
constructor(private _service: OAuth2Service) {}
|
||||||
|
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer.apply(CSRFMiddleware, UserMiddleware).forRoutes(OAuth2Controller);
|
||||||
consumer.apply(this._service.oauth.express()).forRoutes('oauth2/*');
|
consumer.apply(this._service.oauth.express()).forRoutes('oauth2/*');
|
||||||
consumer
|
consumer
|
||||||
.apply(AuthMiddleware, ValidateCSRFMiddleware)
|
.apply(AuthMiddleware, ValidateCSRFMiddleware)
|
||||||
|
@ -4,7 +4,9 @@ import {
|
|||||||
NestModule,
|
NestModule,
|
||||||
RequestMethod,
|
RequestMethod,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
||||||
|
import { UserMiddleware } from 'src/middleware/user.middleware';
|
||||||
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
||||||
import { UserModule } from 'src/modules/objects/user/user.module';
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
import { RegisterController } from './register.controller';
|
import { RegisterController } from './register.controller';
|
||||||
@ -15,6 +17,10 @@ import { RegisterController } from './register.controller';
|
|||||||
})
|
})
|
||||||
export class RegisterModule implements NestModule {
|
export class RegisterModule implements NestModule {
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer
|
||||||
|
.apply(CSRFMiddleware, UserMiddleware)
|
||||||
|
.forRoutes(RegisterController);
|
||||||
|
|
||||||
consumer
|
consumer
|
||||||
.apply(ValidateCSRFMiddleware)
|
.apply(ValidateCSRFMiddleware)
|
||||||
.forRoutes({ path: 'register*', method: RequestMethod.POST });
|
.forRoutes({ path: 'register*', method: RequestMethod.POST });
|
||||||
|
@ -21,6 +21,8 @@ import { UserTokenModule } from 'src/modules/objects/user-token/user-token.modul
|
|||||||
import { OAuth2Module } from '../../oauth2/oauth2.module';
|
import { OAuth2Module } from '../../oauth2/oauth2.module';
|
||||||
import { SettingsController } from './settings.controller';
|
import { SettingsController } from './settings.controller';
|
||||||
import { SettingsService } from './settings.service';
|
import { SettingsService } from './settings.service';
|
||||||
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
|
import { UserMiddleware } from 'src/middleware/user.middleware';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [SettingsController],
|
controllers: [SettingsController],
|
||||||
@ -69,6 +71,9 @@ import { SettingsService } from './settings.service';
|
|||||||
})
|
})
|
||||||
export class SettingsModule implements NestModule {
|
export class SettingsModule implements NestModule {
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer
|
||||||
|
.apply(CSRFMiddleware, UserMiddleware)
|
||||||
|
.forRoutes(SettingsController);
|
||||||
consumer
|
consumer
|
||||||
.apply(ValidateCSRFMiddleware)
|
.apply(ValidateCSRFMiddleware)
|
||||||
.forRoutes(
|
.forRoutes(
|
||||||
|
@ -1,11 +1,4 @@
|
|||||||
import {
|
import { Module } from '@nestjs/common';
|
||||||
MiddlewareConsumer,
|
|
||||||
Module,
|
|
||||||
NestModule,
|
|
||||||
RequestMethod,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
|
||||||
import { UserMiddleware } from 'src/middleware/user.middleware';
|
|
||||||
import { ConfigurationModule } from '../config/config.module';
|
import { ConfigurationModule } from '../config/config.module';
|
||||||
import { JWTModule } from '../jwt/jwt.module';
|
import { JWTModule } from '../jwt/jwt.module';
|
||||||
import { ObjectsModule } from '../objects/objects.module';
|
import { ObjectsModule } from '../objects/objects.module';
|
||||||
@ -32,15 +25,4 @@ import { TwoFactorModule } from './two-factor/two-factor.module';
|
|||||||
providers: [],
|
providers: [],
|
||||||
exports: [],
|
exports: [],
|
||||||
})
|
})
|
||||||
export class StaticFrontEndModule implements NestModule {
|
export class StaticFrontEndModule {}
|
||||||
configure(consumer: MiddlewareConsumer) {
|
|
||||||
consumer
|
|
||||||
.apply(CSRFMiddleware, UserMiddleware)
|
|
||||||
.exclude(
|
|
||||||
{ path: 'uploads*', method: RequestMethod.ALL },
|
|
||||||
{ path: 'public*', method: RequestMethod.ALL },
|
|
||||||
{ path: 'api*', method: RequestMethod.ALL },
|
|
||||||
)
|
|
||||||
.forRoutes('*');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
||||||
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
||||||
|
import { UserMiddleware } from 'src/middleware/user.middleware';
|
||||||
import { UserTokenModule } from 'src/modules/objects/user-token/user-token.module';
|
import { UserTokenModule } from 'src/modules/objects/user-token/user-token.module';
|
||||||
import { UserModule } from 'src/modules/objects/user/user.module';
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
import { TwoFactorController } from './two-factor.controller';
|
import { TwoFactorController } from './two-factor.controller';
|
||||||
@ -11,6 +13,9 @@ import { TwoFactorController } from './two-factor.controller';
|
|||||||
})
|
})
|
||||||
export class TwoFactorModule implements NestModule {
|
export class TwoFactorModule implements NestModule {
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer
|
||||||
|
.apply(CSRFMiddleware, UserMiddleware)
|
||||||
|
.forRoutes(TwoFactorController);
|
||||||
consumer.apply(AuthMiddleware).forRoutes('account/two-factor/activate');
|
consumer.apply(AuthMiddleware).forRoutes('account/two-factor/activate');
|
||||||
consumer.apply(FlashMiddleware).forRoutes('account/two-factor/activate');
|
consumer.apply(FlashMiddleware).forRoutes('account/two-factor/activate');
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user